| /* |
| * Samsung Exynos SoC series VPU driver |
| * |
| * Copyright (c) 2015 Samsung Electronics Co., Ltd |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| */ |
| |
| #include <linux/delay.h> |
| #include <linux/slab.h> |
| |
| #include "lib/vpul-ds.h" |
| #include "vpu-graphmgr.h" |
| #include "vpu-graph.h" |
| #include "vpuo-vertex.h" |
| #include "vpuo-chain.h" |
| #include "vpu-debug.h" |
| #include "vpu-exynos.h" |
| #include "vs4l.h" |
| |
| const struct vpu_graph_ops vpu_graph_ops; |
| |
| static struct vpuo_pu * __vpu_graph_find_iopu(struct list_head *list, u32 target) |
| { |
| struct vpuo_pu *pu, *temp; |
| |
| list_for_each_entry_safe(pu, temp, list, gleaf_entry) { |
| if (pu->target == target) |
| return pu; |
| } |
| |
| return NULL; |
| } |
| |
| static struct vpuo_pu * __vpu_graph_find_pu(struct vpu_graph *graph, u32 target) |
| { |
| struct vpuo_vertex *vertex; |
| struct vpuo_chain *chain; |
| struct vpuo_pu *pu; |
| u32 chain_id, pu_id; |
| u32 i, j; |
| |
| pu = NULL; |
| chain_id = (target >> VS4L_TARGET_SC_SHIFT) & VS4L_TARGET_SC; |
| pu_id = (target >> VS4L_TARGET_PU_SHIFT) & VS4L_TARGET_PU; |
| |
| for (i = 0; i < graph->vertex_cnt; ++i) { |
| vertex = graph->vertex_array[i]; |
| for (j = 0; j < vertex->chain_cnt; ++j) { |
| chain = vertex->chain_array[j]; |
| |
| if (chain->id != chain_id) |
| continue; |
| |
| pu = chain->pu_table[pu_id]; |
| } |
| } |
| |
| return pu; |
| } |
| |
| static void __vpu_graph_connect_chain(struct vpuo_chain *src_chain, struct vpuo_chain *dst_chain) |
| { |
| u32 i, connected = 0; |
| |
| for (i = 0; i < src_chain->otchain_cnt; ++i) { |
| if (src_chain->otchain[i] == dst_chain) |
| connected++; |
| } |
| |
| if (!connected) { |
| src_chain->otchain[src_chain->otchain_cnt] = dst_chain; |
| src_chain->otchain_cnt++; |
| |
| dst_chain->inchain[dst_chain->inchain_cnt] = src_chain; |
| dst_chain->inchain_cnt++; |
| |
| BUG_ON(src_chain->otchain_cnt >= VPUO_CHAIN_MAX_PORT); |
| BUG_ON(dst_chain->inchain_cnt >= VPUO_CHAIN_MAX_PORT); |
| } |
| } |
| |
| static int __vpu_graph_print(struct vpu_graph *graph) |
| { |
| DLOG_INIT(); |
| u32 i, j; |
| struct list_head *lvl_list, *list; |
| struct vpuo_vertex *vertex, *vtemp; |
| struct vpuo_chain *chain; |
| struct vpuo_pu *pu, *ptemp; |
| |
| BUG_ON(!graph); |
| BUG_ON(!graph->global_lock); |
| |
| mutex_lock(graph->global_lock); |
| |
| vpu_iinfo("[GRAPH : %d]\n", graph, graph->uid); |
| |
| lvl_list = graph->lvl_list; |
| if (!lvl_list) { |
| vpu_ierr("lvl_list is NULL\n", graph); |
| mutex_unlock(graph->global_lock); |
| return -EINVAL; |
| } |
| |
| for (i = 0; i < VPU_GRAPH_MAX_LEVEL; ++i) { |
| if (list_empty(&lvl_list[i])) |
| continue; |
| |
| DLOG("lvl%d : ", i); |
| list_for_each_entry_safe(vertex, vtemp, &lvl_list[i], level_entry) { |
| DLOG("%d(", vertex->id); |
| |
| if (vertex->otvertex_cnt >= 1) { |
| for (j = 0; j < (vertex->otvertex_cnt - 1); ++j) |
| DLOG("%d ", vertex->otvertex[j]->id); |
| DLOG("%d) ", vertex->otvertex[j]->id); |
| } else { |
| DLOG(") "); |
| } |
| } |
| |
| vpu_info("%s\n", DLOG_OUT()); |
| } |
| |
| for (i = 0; i < VPU_GRAPH_MAX_LEVEL; ++i) { |
| if (list_empty(&lvl_list[i])) |
| continue; |
| |
| list_for_each_entry_safe(vertex, vtemp, &lvl_list[i], level_entry) { |
| vpuo_vertex_print(vertex); |
| } |
| } |
| |
| DLOG("in :"); |
| list = &graph->inleaf_list; |
| list_for_each_entry_safe(pu, ptemp, list, gleaf_entry) { |
| chain = pu->parent; |
| DLOG(" %d(%d)", pu->id, chain->id); |
| } |
| vpu_info("%s\n", DLOG_OUT()); |
| |
| DLOG("ot :"); |
| list = &graph->otleaf_list; |
| list_for_each_entry_safe(pu, ptemp, list, gleaf_entry) { |
| chain = pu->parent; |
| DLOG(" %d(%d)", pu->id, chain->id); |
| } |
| vpu_info("%s\n", DLOG_OUT()); |
| |
| mutex_unlock(graph->global_lock); |
| |
| return 0; |
| } |
| |
| static int __vpu_graph_resource_get(struct vpu_graph *graph) |
| { |
| int ret = 0; |
| |
| if (test_bit(VPU_GRAPH_STATE_HENROLL, &graph->state)) { |
| vpu_ierr("resource is already refered\n", graph); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| ret = vpu_resource_add(graph->resource, graph->desc_utask); |
| if (ret) { |
| vpu_ierr("vpu_resource_add ia fail(%d)\n", graph, ret); |
| goto p_err; |
| } |
| |
| set_bit(VPU_GRAPH_STATE_HENROLL, &graph->state); |
| |
| if (test_bit(VPU_GRAPH_STATE_HMAPPED, &graph->state)) { |
| vpu_ierr("resource is already mapped\n", graph); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| ret = vpu_resource_get(graph->resource, graph->desc_mtask, graph->flags); |
| if (ret) { |
| vpu_ierr("vpu_resource_get ia fail(%d)\n", graph, ret); |
| goto p_err; |
| } |
| |
| set_bit(VPU_GRAPH_STATE_HMAPPED, &graph->state); |
| |
| p_err: |
| return ret; |
| } |
| |
| static int __vpu_graph_resource_put(struct vpu_graph *graph) |
| { |
| int ret = 0; |
| |
| if (test_bit(VPU_GRAPH_STATE_HENROLL, &graph->state)) { |
| ret = vpu_resource_del(graph->resource, graph->desc_utask); |
| if (ret) |
| vpu_ierr("vpu_resource_del ia fail(%d)\n", graph, ret); |
| } |
| |
| clear_bit(VPU_GRAPH_STATE_HENROLL, &graph->state); |
| |
| if (test_bit(VPU_GRAPH_STATE_HMAPPED, &graph->state)) { |
| ret = vpu_resource_put(graph->resource, graph->desc_mtask); |
| if (ret) |
| vpu_ierr("vpu_resource_put ia fail(%d)\n", graph, ret); |
| } |
| |
| clear_bit(VPU_GRAPH_STATE_HMAPPED, &graph->state); |
| |
| return ret; |
| } |
| |
| static int __vpu_graph_start(struct vpu_graph *graph) |
| { |
| int ret = 0; |
| |
| BUG_ON(!graph); |
| |
| if (test_bit(VPU_GRAPH_STATE_START, &graph->state)) |
| return 0; |
| |
| ret = __vpu_graph_resource_get(graph); |
| if (ret) { |
| vpu_ierr("__vpu_graph_resource_get is fail(%d)\n", graph, ret); |
| goto p_err; |
| } |
| |
| ret = vpu_graphmgr_grp_start(graph->cookie, graph); |
| if (ret) { |
| vpu_ierr("vpu_graphmgr_grp_start is fail(%d)\n", graph, ret); |
| goto p_err; |
| } |
| |
| set_bit(VPU_GRAPH_STATE_START, &graph->state); |
| |
| p_err: |
| return ret; |
| } |
| |
| static int __vpu_graph_stop(struct vpu_graph *graph) |
| { |
| int ret = 0, errcnt = 0; |
| u32 retry, timeout; |
| struct vpu_framemgr *framemgr; |
| struct vpu_frame *control; |
| |
| if (!test_bit(VPU_GRAPH_STATE_START, &graph->state)) |
| return 0; |
| |
| framemgr = &graph->framemgr; |
| if (framemgr->req_cnt + framemgr->pre_cnt) { |
| control = &graph->control; |
| control->message = VPU_CTRL_STOP; |
| vpu_graphmgr_queue(graph->cookie, control); |
| timeout = wait_event_timeout(graph->control_wq, |
| control->message == VPU_CTRL_STOP_DONE, VPU_GRAPH_STOP_TIMEOUT); |
| if (!timeout) { |
| vpu_ierr("wait_event_timeout is expired\n", graph); |
| errcnt++; |
| } |
| } |
| |
| retry = VPU_STOP_WAIT_COUNT; |
| while (--retry && framemgr->req_cnt) { |
| vpu_iwarn("waiting %d request cancel...(%d)\n", graph, framemgr->req_cnt, retry); |
| msleep(10); |
| } |
| |
| if (!retry) { |
| vpu_ierr("request cancel is fail\n", graph); |
| errcnt++; |
| } |
| |
| retry = VPU_STOP_WAIT_COUNT; |
| while (--retry && framemgr->pre_cnt) { |
| vpu_iwarn("waiting %d prepare cancel...(%d)\n", graph, framemgr->pre_cnt, retry); |
| msleep(10); |
| } |
| |
| if (!retry) { |
| vpu_ierr("prepare cancel is fail\n", graph); |
| errcnt++; |
| } |
| |
| retry = VPU_STOP_WAIT_COUNT; |
| while (--retry && framemgr->pro_cnt) { |
| vpu_iwarn("waiting %d process done...(%d)\n", graph, framemgr->pro_cnt, retry); |
| msleep(10); |
| } |
| |
| if (!retry) { |
| vpu_ierr("process done is fail\n", graph); |
| errcnt++; |
| } |
| |
| ret = __vpu_graph_resource_put(graph); |
| if (ret) { |
| vpu_ierr("__vpu_graph_resource_put is fail(%d)\n", graph, ret); |
| errcnt++; |
| } |
| |
| ret = vpu_graphmgr_grp_stop(graph->cookie, graph); |
| if (ret) { |
| vpu_ierr("vpu_graphmgr_grp_stop is fail(%d)\n", graph, ret); |
| errcnt++; |
| } |
| |
| vpu_frame_flush(framemgr); |
| /* this copy is necessary for resetting task info otherwise execution of the task will be timeout */ |
| memcpy(graph->desc_mtask, graph->desc_utask, graph->size); |
| |
| clear_bit(VPU_GRAPH_STATE_START, &graph->state); |
| |
| return errcnt; |
| } |
| |
| static int __vpu_graph_unmap(struct vpu_graph *graph) |
| { |
| int ret = 0; |
| struct vpu_memory_buffer *buffer; |
| u32 i; |
| |
| for (i = 0; i < graph->imbuffer_cnt; ++i) { |
| buffer = graph->imbuffer_table[i].handle; |
| if (!buffer) { |
| vpu_ierr("buffer is NULL(%d)\n", graph, i); |
| continue; |
| } |
| |
| ret = vpu_memory_unmap(graph->memory, buffer); |
| if (ret) |
| vpu_ierr("vpu_memory_unmap is fail(%d)\n", graph, ret); |
| |
| graph->imbuffer_table[i].fd = 0; |
| graph->imbuffer_table[i].handle = NULL; |
| kfree(buffer); |
| } |
| |
| graph->imbuffer_cnt = 0; |
| clear_bit(VPU_GRAPH_STATE_MMAPPED, &graph->state); |
| |
| return ret; |
| } |
| |
| static int __vpu_graph_map(struct vpu_graph *graph) |
| { |
| int ret = 0; |
| struct vpul_task *task; |
| struct vpu_memory_buffer *buffer; |
| u32 i, j; |
| |
| if (test_bit(VPU_GRAPH_STATE_MMAPPED, &graph->state)) { |
| vpu_iwarn("graph is already mapped\n", graph); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| task = graph->desc_mtask; |
| graph->imbuffer_cnt = 0; |
| graph->iobuffer_cnt = 0; |
| |
| for (i = 0; i < task->n_external_mem_addresses; ++i) { |
| if (task->external_mem_addr[i]) { |
| buffer = kzalloc(sizeof(struct vpu_memory_buffer), GFP_KERNEL); |
| if (!buffer) { |
| vpu_err("kzalloc is fail\n"); |
| ret = -ENOMEM; |
| goto p_err; |
| } |
| |
| buffer->fd = task->external_mem_addr[i]; |
| |
| ret = vpu_memory_map(graph->memory, buffer); |
| if (ret) { |
| vpu_ierr("vpu_memory_map(%d) is fail(%d)\n", graph, i, ret); |
| for (j = 0; j < task->n_external_mem_addresses; ++j) |
| vpu_info("[DUMP EXT%d] 0x%X\n", j, task->external_mem_addr[j]); |
| goto p_err; |
| } |
| |
| if (buffer->dvaddr < VPU_AHB_BASE_ADDR) { |
| vpu_ierr("dvaddr is invalid(%pa)\n", graph, &buffer->dvaddr); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| vpu_iinfo("imbuffer[%d] : %d(%d) -> %pa\n", graph, graph->imbuffer_cnt, |
| buffer->fd, i, &buffer->dvaddr); |
| |
| task->external_mem_addr[i] = buffer->dvaddr - VPU_AHB_BASE_ADDR; |
| graph->imbuffer_table[graph->imbuffer_cnt].buffer_index = i; |
| graph->imbuffer_table[graph->imbuffer_cnt].buffer = &task->external_mem_addr[i]; |
| graph->imbuffer_table[graph->imbuffer_cnt].handle = buffer; |
| graph->imbuffer_table[graph->imbuffer_cnt].fd = buffer->fd; |
| graph->imbuffer_cnt++; |
| |
| BUG_ON(graph->imbuffer_cnt >= VPU_GRAPH_MAX_INTERMEDIATE); |
| } else { |
| graph->iobuffer_idx[graph->iobuffer_cnt] = i; |
| graph->iobuffer_dat[graph->iobuffer_cnt] = 0; |
| graph->iobuffer_cnt++; |
| } |
| } |
| |
| set_bit(VPU_GRAPH_STATE_MMAPPED, &graph->state); |
| return 0; |
| |
| p_err: |
| __vpu_graph_unmap(graph); |
| return ret; |
| } |
| |
| static int __vpu_graph_alloc(struct vpu_graph *graph) |
| { |
| int ret = 0; |
| char *desc_ubase, *desc_mbase; |
| u32 i, vertex_cnt; |
| struct vpul_task *desc_utask, *desc_mtask; |
| struct vpul_vertex *desc_uvertex, *desc_mvertex; |
| struct vpuo_vertex *vertex; |
| |
| if (test_bit(VS4L_GRAPH_FLAG_PRIMITIVE, &graph->flags)) |
| return 0; |
| |
| desc_utask = graph->desc_utask; |
| desc_mtask = graph->desc_mtask; |
| desc_ubase = (char *)desc_utask; |
| desc_mbase = (char *)desc_mtask; |
| |
| /* 1. checking data integration */ |
| if ((desc_ubase[graph->size - 4] != 'V') || |
| (desc_ubase[graph->size - 3] != 'S') || |
| (desc_ubase[graph->size - 2] != '4') || |
| (desc_ubase[graph->size - 1] != 'L')) { |
| vpu_ierr("magic number(%c %c %c %c) is invalid\n", graph, |
| desc_ubase[graph->size - 4], desc_ubase[graph->size - 3], |
| desc_ubase[graph->size - 2], desc_ubase[graph->size - 1]); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| if (desc_utask->id == 0) { |
| vpu_ierr("task id is ZERO\n", graph); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| vertex_cnt = desc_utask->t_num_of_vertices; |
| if (!vertex_cnt) { |
| vpu_ierr("vertex_cnt is ZERO\n", graph); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| if (vertex_cnt >= VPU_GRAPH_MAX_VERTEX) { |
| vpu_ierr("vertex_cnt is invalid(%d)\n", graph, vertex_cnt); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| /* 2. allocation chain & aquire sequential chain information */ |
| desc_uvertex = (struct vpul_vertex *)(desc_ubase + desc_utask->vertices_vec_ofs); |
| desc_mvertex = (struct vpul_vertex *)(desc_mbase + desc_mtask->vertices_vec_ofs); |
| for (i = 0; i < vertex_cnt; ++i) { |
| ret = vpuo_vertex_create(&vertex, desc_ubase, desc_mbase, &desc_uvertex[i], &desc_mvertex[i], graph); |
| if (ret) { |
| vpu_ierr("vpuo_vertex_create is fail(%d)\n", graph, ret); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| if (!vertex) { |
| vpu_ierr("vertex is NULL\n", graph); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| graph->vertex_array[graph->vertex_cnt] = vertex; |
| graph->vertex_table[graph->vertex_cnt] = i; |
| graph->vertex_cnt++; |
| |
| BUG_ON(graph->vertex_cnt >= VPU_GRAPH_MAX_VERTEX); |
| } |
| |
| |
| graph->update_cnt = desc_utask->t_num_of_pu_params_on_invoke; |
| if (graph->update_cnt) { |
| u32 update_size = graph->update_cnt * sizeof(union vpul_pu_parameters); |
| |
| graph->update_array = kmalloc(update_size, GFP_KERNEL); |
| if (!graph->update_array) { |
| vpu_ierr("kmalloc is fail(%d)\n", graph, update_size); |
| goto p_err; |
| } |
| } |
| |
| p_err: |
| return ret; |
| } |
| |
| static int __vpu_graph_free(struct vpu_graph *graph) |
| { |
| int ret = 0; |
| u32 i, vertex_cnt; |
| struct vpuo_vertex *vertex; |
| |
| if (test_bit(VS4L_GRAPH_FLAG_PRIMITIVE, &graph->flags)) |
| return 0; |
| |
| kfree(graph->update_array); |
| graph->update_cnt = 0; |
| |
| vertex_cnt = graph->vertex_cnt; |
| for (i = 0; i < vertex_cnt; ++i) { |
| vertex = graph->vertex_array[i]; |
| |
| ret = vpuo_vertex_destroy(vertex); |
| if (ret) { |
| vpu_err("vpuo_vertex_destroy is fail(%d)\n", ret); |
| continue; |
| } |
| |
| graph->vertex_array[i] = NULL; |
| graph->vertex_table[i] = 0; |
| graph->vertex_cnt--; |
| } |
| |
| return ret; |
| } |
| |
| static int __vpu_graph_parse(struct vpu_graph *graph) |
| { |
| int ret = 0; |
| struct list_head *lvl_list; |
| struct list_head *inleaf_list, *otleaf_list; |
| struct vpul_vertex *desc_src; |
| struct vpul_edge *desc_uedge; |
| struct vpuo_vertex *vertex, *src, *dst, *target, *temp; |
| struct vpuo_chain *chain, *src_chain, *dst_chain; |
| struct vpuo_pu *inpu, *inpu2, *otpu, *t1, *t2, *pu; |
| u32 vertex_cnt, chain_cnt, pu_cnt; |
| u32 lvl_vertex_cnt, edge_cnt; |
| u32 i, j, k; |
| u32 matched; |
| |
| if (test_bit(VS4L_GRAPH_FLAG_PRIMITIVE, &graph->flags)) |
| return 0; |
| |
| /* 1. parsing each vertex */ |
| vertex_cnt = graph->vertex_cnt; |
| for (i = 0; i < vertex_cnt; ++i) { |
| vertex = graph->vertex_array[i]; |
| if (!vertex) { |
| vpu_ierr("vertex is NULL(%d)\n", graph, i); |
| BUG(); |
| } |
| |
| ret = vpuo_vertex_parse(vertex); |
| if (ret) { |
| vpu_ierr("vpuo_vertex_parse is fail(%d)\n", graph, ret); |
| goto p_err; |
| } |
| } |
| |
| /* 2. weaving */ |
| for (i = 0; i < vertex_cnt; ++i) { |
| src = graph->vertex_array[i]; |
| if (!src) { |
| vpu_ierr("src is NULL(%d)\n", graph, i); |
| BUG(); |
| } |
| |
| desc_src = src->desc_uvertex; |
| if (!desc_src) { |
| vpu_ierr("desc_uvertex is NULL(%d)\n", graph, i); |
| BUG(); |
| } |
| |
| edge_cnt = desc_src->n_out_edges; |
| desc_uedge = desc_src->out_edges; |
| for (j = 0; j < edge_cnt; ++j) { |
| if (desc_uedge[j].dst_vtx_idx >= vertex_cnt) { |
| vpu_ierr("dst vertex index(%d) is invalid\n", graph, desc_uedge[j].dst_vtx_idx); |
| BUG(); |
| } |
| |
| dst = graph->vertex_array[desc_uedge[j].dst_vtx_idx]; |
| if (!dst) { |
| vpu_ierr("dst is NULL(%d)\n", graph, i); |
| BUG(); |
| } |
| |
| src->otvertex[src->otvertex_cnt] = dst; |
| src->otvertex_cnt++; |
| dst->invertex[dst->invertex_cnt] = src; |
| dst->invertex_cnt++; |
| |
| BUG_ON(src->otvertex_cnt >= VPU_VERTEX_MAX_PORT); |
| BUG_ON(dst->invertex_cnt >= VPU_VERTEX_MAX_PORT); |
| } |
| } |
| |
| /* 3. stitching */ |
| for (i = 0; i < vertex_cnt; ++i) { |
| src = graph->vertex_array[i]; |
| if (!src) { |
| vpu_err("src is NULL\n"); |
| BUG(); |
| } |
| |
| for (j = 0; j < src->otvertex_cnt; ++j) { |
| dst = src->otvertex[j]; |
| if (!dst) { |
| vpu_err("dst is NULL\n"); |
| BUG(); |
| } |
| |
| otleaf_list = &src->otleaf_list; |
| inleaf_list = &dst->inleaf_list; |
| list_for_each_entry_safe(otpu, t1, otleaf_list, vleaf_entry) { |
| if (otpu->buffer_cnt == 0) |
| continue; |
| |
| list_for_each_entry_safe(inpu, t2, inleaf_list, vleaf_entry) { |
| /* HACK : search buffer index only at last and first layer */ |
| for (k = 0; k < dst->layers; ++k) { |
| matched = 0; |
| |
| if ((otpu->buffer[otpu->buffer_cnt - 1] == inpu->buffer[k]) && |
| (inpu->buffer[k] != 0)) |
| matched = 1; |
| |
| if (otpu->buffer_idx[otpu->buffer_cnt - 1] == inpu->buffer_idx[k]) |
| matched = 1; |
| |
| if (matched) { |
| inpu->buffer_shm[k]++; |
| inpu->inpu[inpu->inpu_cnt] = otpu; |
| inpu->inpu_cnt++; |
| if (inpu->inpu_cnt >= inpu->buffer_cnt) |
| set_bit(VPUO_PU_STATE_IM, &inpu->state); |
| |
| otpu->buffer_shm[otpu->buffer_cnt - 1]++; |
| otpu->otpu[otpu->otpu_cnt] = inpu; |
| otpu->otpu_cnt++; |
| if (otpu->otpu_cnt >= otpu->buffer_cnt) |
| set_bit(VPUO_PU_STATE_IM, &otpu->state); |
| |
| src_chain = otpu->parent; |
| dst_chain = inpu->parent; |
| __vpu_graph_connect_chain(src_chain, dst_chain); |
| |
| BUG_ON(inpu->inpu_cnt >= VPUO_PU_MAX_PORT); |
| BUG_ON(otpu->otpu_cnt >= VPUO_PU_MAX_PORT); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /* 4. leveling */ |
| lvl_vertex_cnt = 0; |
| graph->lvl_cnt = 0; |
| lvl_list = graph->lvl_list; |
| for (i = 0; i < VPU_GRAPH_MAX_LEVEL; ++i) |
| INIT_LIST_HEAD(&lvl_list[i]); |
| |
| for (i = 0; i < vertex_cnt; ++i) { |
| vertex = graph->vertex_array[i]; |
| if (!vertex) { |
| vpu_ierr("vertex is NULL\n", graph); |
| BUG(); |
| } |
| |
| if (!vertex->invertex_cnt) { |
| list_add_tail(&vertex->level_entry, &lvl_list[0]); |
| vertex->level = 0; |
| lvl_vertex_cnt++; |
| } |
| } |
| |
| if (!lvl_vertex_cnt) { |
| vpu_ierr("the number of first level entry is zero\n", graph); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| for (i = 0; i < (VPU_GRAPH_MAX_LEVEL - 1); ++i) { |
| if (list_empty(&lvl_list[i])) |
| break; |
| |
| list_for_each_entry_safe(vertex, temp, &lvl_list[i], level_entry) { |
| for (j = 0; j < vertex->invertex_cnt; ++j) { |
| target = vertex->invertex[j]; |
| if (!target) { |
| vpu_ierr("target is NULL\n", graph); |
| BUG(); |
| } |
| |
| if (target->level >= i) { |
| list_del(&vertex->level_entry); |
| lvl_vertex_cnt--; |
| |
| list_add_tail(&vertex->level_entry, &lvl_list[i + 1]); |
| vertex->level = i + 1; |
| lvl_vertex_cnt++; |
| break; |
| } |
| } |
| |
| if (vertex->level != i) |
| continue; |
| |
| for (j = 0; j < vertex->otvertex_cnt; ++j) { |
| target = vertex->otvertex[j]; |
| if (!target) { |
| vpu_ierr("target is NULL\n", graph); |
| BUG(); |
| } |
| |
| /* if already is added */ |
| if (target->level < VPU_GRAPH_MAX_LEVEL) |
| continue; |
| |
| list_add_tail(&target->level_entry, &lvl_list[i + 1]); |
| target->level = i + 1; |
| lvl_vertex_cnt++; |
| } |
| } |
| } |
| |
| if (lvl_vertex_cnt != vertex_cnt) { |
| vpu_ierr("connection is invalid(%d, %d)\n", graph, lvl_vertex_cnt, vertex_cnt); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| graph->lvl_cnt = i; |
| |
| /* 5. pick up leaf */ |
| graph->inleaf_cnt = 0; |
| INIT_LIST_HEAD(&graph->inleaf_list); |
| graph->otleaf_cnt = 0; |
| INIT_LIST_HEAD(&graph->otleaf_list); |
| |
| for (i = 0; i < vertex_cnt; ++i) { |
| vertex = graph->vertex_array[i]; |
| if (!vertex) { |
| vpu_err("vertex is NULL\n"); |
| BUG(); |
| } |
| |
| inleaf_list = &vertex->inleaf_list; |
| list_for_each_entry_safe(inpu, t1, inleaf_list, vleaf_entry) { |
| if (test_bit(VPUO_PU_STATE_IM, &inpu->state)) |
| continue; |
| |
| graph->inleaf_cnt++; |
| list_add_tail(&inpu->gleaf_entry, &graph->inleaf_list); |
| } |
| |
| otleaf_list = &vertex->otleaf_list; |
| list_for_each_entry_safe(otpu, t2, otleaf_list, vleaf_entry) { |
| if (test_bit(VPUO_PU_STATE_IM, &otpu->state)) |
| continue; |
| |
| graph->otleaf_cnt++; |
| list_add_tail(&otpu->gleaf_entry, &graph->otleaf_list); |
| } |
| } |
| |
| /* 6. remove duplicated io */ |
| inleaf_list = &graph->inleaf_list; |
| list_for_each_entry_safe(inpu, t1, inleaf_list, gleaf_entry) { |
| if (!test_bit(VPUO_PU_STATE_IN, &inpu->state)) |
| continue; |
| |
| inpu2 = list_next_entry(inpu, gleaf_entry); |
| list_for_each_entry_safe_from(inpu2, t2, inleaf_list, gleaf_entry) { |
| if (!test_bit(VPUO_PU_STATE_IN, &inpu2->state)) |
| continue; |
| |
| if (inpu->buffer_idx[0] == inpu2->buffer_idx[0]) |
| clear_bit(VPUO_PU_STATE_IN, &inpu2->state); |
| } |
| } |
| |
| list_for_each_entry_safe(inpu, t1, inleaf_list, gleaf_entry) { |
| if (!test_bit(VPUO_PU_STATE_IN, &inpu->state)) { |
| list_del(&inpu->gleaf_entry); |
| graph->inleaf_cnt--; |
| } |
| } |
| |
| /* 7. verification */ |
| for (i = 0; i < vertex_cnt; ++i) { |
| vertex = graph->vertex_array[i]; |
| if (!vertex) { |
| vpu_err("vertex is NULL\n"); |
| BUG(); |
| } |
| |
| chain_cnt = vertex->chain_cnt; |
| for (j = 0; j < chain_cnt; ++j) { |
| chain = vertex->chain_array[j]; |
| if (!chain) { |
| vpu_err("chain is NULL\n"); |
| BUG(); |
| } |
| |
| inleaf_list = &chain->inleaf_list; |
| list_for_each_entry_safe(inpu, t1, inleaf_list, cleaf_entry) { |
| if (test_bit(VPUO_PU_STATE_OT, &inpu->state)) { |
| vpu_ierr("pu %d have invalid OT flag\n", graph, inpu->id); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| if (test_bit(VPUO_PU_STATE_IM, &inpu->state) && !inpu->buffer_cnt) { |
| vpu_ierr("pu %d have invalid buffer cnt(%d)\n", graph, inpu->id, inpu->buffer_cnt); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| if (test_bit(VPUO_PU_STATE_IM, &inpu->state) && !inpu->inpu_cnt) { |
| vpu_ierr("pu %d should HAVE inputs\n", graph, inpu->id); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| } |
| |
| otleaf_list = &chain->otleaf_list; |
| list_for_each_entry_safe(otpu, t2, otleaf_list, cleaf_entry) { |
| if (test_bit(VPUO_PU_STATE_IN, &otpu->state)) { |
| vpu_ierr("pu %d have invalid IN flag\n", graph, otpu->id); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| if (test_bit(VPUO_PU_STATE_IM, &otpu->state) && !otpu->buffer_cnt) { |
| vpu_ierr("pu %d have invalid buffer cnt(%d)\n", graph, otpu->id, otpu->buffer_cnt); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| if (test_bit(VPUO_PU_STATE_IM, &otpu->state) && !otpu->otpu_cnt) { |
| vpu_ierr("pu %d should HAVE outputs\n", graph, otpu->id); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| } |
| } |
| } |
| |
| /* 8. pu bitmap for debugging */ |
| for (i = 0; i < vertex_cnt; ++i) { |
| vertex = graph->vertex_array[i]; |
| if (!vertex) { |
| vpu_err("vertex is NULL\n"); |
| BUG(); |
| } |
| |
| chain_cnt = vertex->chain_cnt; |
| for (j = 0; j < chain_cnt; ++j) { |
| chain = vertex->chain_array[j]; |
| if (!chain) { |
| vpu_err("chain is NULL\n"); |
| BUG(); |
| } |
| |
| pu_cnt = chain->pu_cnt; |
| for (k = 0; k < pu_cnt; ++k) { |
| pu = chain->pu_array[k]; |
| if (!pu) { |
| vpu_err("pu is NULL\n"); |
| BUG(); |
| } |
| |
| graph->pu_map[pu->id]++; |
| } |
| } |
| } |
| |
| p_err: |
| __vpu_graph_print(graph); |
| return ret; |
| } |
| |
| void vpu_graph_task_print(struct vpu_graph *graph) |
| { |
| int i, j, k, l; |
| int n_vertex, n_subchain, n_pu; |
| int n_mem, n_edge, n_iteration; |
| struct vpul_task *task; |
| struct vpul_vertex *vertex; |
| struct vpul_process *process; |
| struct vpul_subchain *subchain; |
| struct vpul_pu *pu; |
| |
| task = graph->desc_mtask; |
| |
| vpu_info("[TASK:%d]\n", task->id); |
| vpu_info("priority : %d\n", task->priority); |
| vpu_info("total_size : %d\n", task->total_size); |
| vpu_info("t_num_of_vertices : %d\n", task->t_num_of_vertices); |
| vpu_info("t_num_of_subchains : %d\n", task->t_num_of_subchains); |
| vpu_info("t_num_of_pus : %d\n", task->t_num_of_pus); |
| |
| n_mem = task->n_memmap_desc; |
| for (i = 0; i < n_mem; ++i) { |
| vpu_info("(MMAP:%d) type : %d, index : %d, w : %d, h : %d, n : %d, l : %d\n", i, |
| task->memmap_desc[i].mtype, |
| task->memmap_desc[i].index, |
| task->memmap_desc[i].image_sizes.width, |
| task->memmap_desc[i].image_sizes.height, |
| task->memmap_desc[i].image_sizes.pixel_bytes, |
| task->memmap_desc[i].image_sizes.line_offset); |
| } |
| |
| n_mem = task->n_external_mem_addresses; |
| for (i = 0; i < n_mem; ++i) { |
| vpu_info("(EXT:%d) addr : 0x%X\n", i, task->external_mem_addr[i]); |
| } |
| |
| n_mem = task->n_internal_rams; |
| vpu_info("n_internal_rams : %d\n", n_mem); |
| /* for (j = 0; j < n_mem; ++j) { |
| vpu_info("(MMAP:%d) %d\n", j, vertex[i].proc.io.memmap_desc_idx[j]); |
| } */ |
| |
| n_vertex = task->t_num_of_vertices; |
| vertex = (struct vpul_vertex *)((char *)task + task->vertices_vec_ofs); |
| for (i = 0; i < n_vertex; ++i) { |
| vpu_info("[VERTEX:%d] %ld\n", i, (ulong)&vertex[i] - (ulong)task); |
| vpu_info("vtype : %d\n", vertex[i].vtype); |
| vpu_info("n_out_edges : %d\n", vertex[i].n_out_edges); |
| |
| n_edge = vertex[i].n_out_edges; |
| for (j = 0; j < n_edge; ++j) { |
| vpu_info("(EDGE:%d) index : %d\n", j, vertex[i].out_edges[j].dst_vtx_idx); |
| } |
| |
| vpu_info("loop.type : %d\n", vertex[i].loop.type); |
| vpu_info("loop.id : %d\n", vertex[i].loop.id); |
| vpu_info("loop.n_end_loop_edges : %d\n", vertex[i].loop.n_end_loop_edges); |
| vpu_info("loop.iterations : %d\n", vertex[i].loop.iterations); |
| |
| vpu_info("num_of_subchains : %d\n", vertex[i].num_of_subchains); |
| |
| if (vertex[i].vtype != VPUL_VERTEXT_PROC) |
| continue; |
| |
| process = &vertex[i].proc; |
| |
| vpu_info("\t" "[PROC] %ld\n", (ulong)process - (ulong)task); |
| |
| n_mem = process->io.n_dynamic_map_rois; |
| vpu_info("\t" "n_dynamic_map_rois : %d\n", n_mem); |
| for (j = 0; j < n_mem; ++j) { |
| vpu_info("\t" "(DROI:%d) %d\n", j, |
| process->io.dynamic_map_roi[j].memmap_idx); |
| } |
| |
| n_mem = process->io.n_fixed_map_roi; |
| vpu_info("\t" "n_fixed_map_roi : %d\n", n_mem); |
| for (j = 0; j < n_mem; ++j) { |
| vpu_info("\t" "(FROI:%d) %d %d %d %d %d\n", j, process->io.fixed_map_roi[j].memmap_idx, |
| process->io.fixed_map_roi[j].roi.first_col, |
| process->io.fixed_map_roi[j].roi.first_line, |
| process->io.fixed_map_roi[j].roi.width, |
| process->io.fixed_map_roi[j].roi.height); |
| } |
| |
| n_iteration = process->io.n_inout_types; |
| vpu_info("\t" "n_inout_types : %d\n", n_iteration); |
| for (j = 0; j < n_iteration; ++j) { |
| vpu_info("\t" "(IOTYPE:%d) %d %d %d\n", j, |
| process->io.inout_types[j].is_dynamic, |
| process->io.inout_types[j].roi_index, |
| process->io.inout_types[j].n_insets_per_dynamic_roi); |
| } |
| |
| n_iteration = process->io.n_sizes_op; |
| vpu_info("\t" "n_sizes_op : %d\n", n_iteration); |
| for (j = 0; j < n_iteration; ++j) { |
| vpu_info("\t" "(SIZE:%d) %d %d %d\n", j, |
| process->io.sizes[j].type, |
| process->io.sizes[j].op_ind, |
| process->io.sizes[j].src_idx); |
| } |
| |
| n_iteration = process->io.n_scales; |
| vpu_info("\t" "n_scales : %d\n", n_iteration); |
| for (j = 0; j < n_iteration; ++j) { |
| vpu_info("\t" "(SCALE:%d) %d/%d %d/%d\n", j, |
| process->io.scales[j].horizontal.numerator, |
| process->io.scales[j].horizontal.denominator, |
| process->io.scales[j].vertical.numerator, |
| process->io.scales[j].vertical.denominator); |
| } |
| |
| n_iteration = process->io.n_croppers; |
| vpu_info("\t" "n_croppers : %d\n", n_iteration); |
| for (j = 0; j < n_iteration; ++j) { |
| vpu_info("\t" "(CROP:%d) %d %d %d %d\n", j, |
| process->io.croppers[j].Left, |
| process->io.croppers[j].Right, |
| process->io.croppers[j].Top, |
| process->io.croppers[j].Bottom); |
| } |
| |
| n_iteration = process->io.n_static_coff; |
| vpu_info("\t" "n_static_coff : %d\n", n_iteration); |
| for (j = 0; j < n_iteration; ++j) { |
| vpu_info("\t" "(SCOFF:%d) %d\n", j, |
| process->io.static_coff[j]); |
| } |
| |
| vpu_info("\t" "param_loop.n_exp_per_sets : %d\n", process->io.param_loop.n_exp_per_sets); |
| vpu_info("\t" "param_loop.n_sets : %d\n", process->io.param_loop.n_sets); |
| vpu_info("\t" "param_loop.fix_inc : %d\n", process->io.param_loop.fix_inc); |
| vpu_info("\t" "param_loop.per_fst : %d\n", process->io.param_loop.per_fst); |
| |
| vpu_info("\t" "n_tiles : %d\n", process->io.n_tiles); |
| vpu_info("\t" "n_insets : %d\n", process->io.n_insets); |
| vpu_info("\t" "n_presets_map_desc : %d\n", process->io.n_presets_map_desc); |
| vpu_info("\t" "n_postsets_map_desc : %d\n", process->io.n_postsets_map_desc); |
| vpu_info("\t" "n_subchain_before_insets : %d\n", process->io.n_subchain_before_insets); |
| vpu_info("\t" "n_subchain_after_insets : %d\n", process->io.n_subchain_after_insets); |
| vpu_info("\t" "n_invocations_per_input_tile : %d\n", process->io.n_invocations_per_input_tile); |
| vpu_info("\t" "max_input_sets_slots : %d\n", process->io.max_input_sets_slots); |
| |
| n_subchain = vertex[i].num_of_subchains; |
| subchain = (struct vpul_subchain *)((char *)task + vertex[i].sc_ofs); |
| |
| for (j = 0; j < n_subchain; ++j) { |
| vpu_info("\t\t" "[SC:%d] %ld\n", j, (ulong)&subchain[j] - (ulong)task); |
| vpu_info("\t\t" "id : %d\n", subchain[j].id); |
| vpu_info("\t\t" "stype : %d\n", subchain[j].stype); |
| vpu_info("\t\t" "num_of_pus : %d\n", subchain[j].num_of_pus); |
| |
| if (subchain[j].stype == VPUL_SUB_CH_HW) { |
| n_pu = subchain[j].num_of_pus; |
| pu = (struct vpul_pu *)((char *)task + subchain[j].pus_ofs); |
| |
| for (k = 0; k < n_pu; ++k) { |
| vpu_info("\t\t\t" "[PU:%d] %ld\n", k, (ulong)&pu[k] - (ulong)task); |
| vpu_info("\t\t\t" "instance : %d\n", pu[k].instance); |
| vpu_info("\t\t\t" "mprb_type : %d\n", pu[k].mprb_type); |
| vpu_info("\t\t\t" "in_size_idx : %d\n", pu[k].in_size_idx); |
| vpu_info("\t\t\t" "out_size_idx : %d\n", pu[k].out_size_idx); |
| vpu_info("\t\t\t" "n_mprbs : %d\n", pu[k].n_mprbs); |
| n_iteration = pu[k].n_mprbs; |
| for (l = 0; l < n_iteration; ++l) { |
| vpu_info("\t\t\t" "(MPRB:%d) %d\n", l, pu[k].mprbs[l]); |
| } |
| |
| switch (pu[k].op_type) { |
| case VPUL_OP_DMA: |
| vpu_info("\t\t\t" "inout_index : %d\n", pu[k].params.dma.inout_index); |
| vpu_info("\t\t\t" "offset_lines_inc : %d\n", pu[k].params.dma.offset_lines_inc); |
| break; |
| case VPUL_OP_FULL_SALB: |
| vpu_info("\t\t\t" "bits_in0 : %d\n", pu[k].params.salb.bits_in0); |
| vpu_info("\t\t\t" "bits_in1 : %d\n", pu[k].params.salb.bits_in1); |
| vpu_info("\t\t\t" "bits_out0 : %d\n", pu[k].params.salb.bits_out0); |
| vpu_info("\t\t\t" "signed_in0 : %d\n", pu[k].params.salb.signed_in0); |
| vpu_info("\t\t\t" "signed_in1 : %d\n", pu[k].params.salb.signed_in1); |
| vpu_info("\t\t\t" "signed_out0 : %d\n", pu[k].params.salb.signed_out0); |
| vpu_info("\t\t\t" "input_enable : %d\n", pu[k].params.salb.input_enable); |
| vpu_info("\t\t\t" "use_mask : %d\n", pu[k].params.salb.use_mask); |
| vpu_info("\t\t\t" "operation_code : %d\n", pu[k].params.salb.operation_code); |
| vpu_info("\t\t\t" "abs_neg : %d\n", pu[k].params.salb.abs_neg); |
| vpu_info("\t\t\t" "trunc_out : %d\n", pu[k].params.salb.trunc_out); |
| vpu_info("\t\t\t" "org_val_med : %d\n", pu[k].params.salb.org_val_med); |
| vpu_info("\t\t\t" "shift_bits : %d\n", pu[k].params.salb.shift_bits); |
| vpu_info("\t\t\t" "cmp_op : %d\n", pu[k].params.salb.cmp_op); |
| vpu_info("\t\t\t" "const_in1 : %d\n", pu[k].params.salb.const_in1); |
| vpu_info("\t\t\t" "thresh_lo : %d\n", pu[k].params.salb.thresh_lo); |
| vpu_info("\t\t\t" "thresh_hi : %d\n", pu[k].params.salb.thresh_hi); |
| vpu_info("\t\t\t" "val_lo : %d\n", pu[k].params.salb.val_lo); |
| vpu_info("\t\t\t" "val_hi : %d\n", pu[k].params.salb.val_hi); |
| vpu_info("\t\t\t" "val_med_filler : %d\n", pu[k].params.salb.val_med_filler); |
| vpu_info("\t\t\t" "salbregs_custom_trunc_en : %d\n", pu[k].params.salb.salbregs_custom_trunc_en); |
| vpu_info("\t\t\t" "salbregs_custom_trunc_bittage : %d\n", pu[k].params.salb.salbregs_custom_trunc_bittage); |
| break; |
| case VPUL_OP_FULL_CALB: |
| vpu_info("\t\t\t" "bits_in0 : %d\n", pu[k].params.calb.bits_in0); |
| vpu_info("\t\t\t" "bits_in1 : %d\n", pu[k].params.calb.bits_in1); |
| vpu_info("\t\t\t" "bits_out0 : %d\n", pu[k].params.calb.bits_out0); |
| vpu_info("\t\t\t" "signed_in0 : %d\n", pu[k].params.calb.signed_in0); |
| vpu_info("\t\t\t" "signed_in1 : %d\n", pu[k].params.calb.signed_in1); |
| vpu_info("\t\t\t" "signed_out0 : %d\n", pu[k].params.calb.signed_out0); |
| vpu_info("\t\t\t" "input_enable : %d\n", pu[k].params.calb.input_enable); |
| vpu_info("\t\t\t" "operation_code : %d\n", pu[k].params.calb.operation_code); |
| vpu_info("\t\t\t" "abs_neg : %d\n", pu[k].params.calb.abs_neg); |
| vpu_info("\t\t\t" "trunc_out : %d\n", pu[k].params.calb.trunc_out); |
| vpu_info("\t\t\t" "org_val_med : %d\n", pu[k].params.calb.org_val_med); |
| vpu_info("\t\t\t" "shift_bits : %d\n", pu[k].params.calb.shift_bits); |
| vpu_info("\t\t\t" "mult_round : %d\n", pu[k].params.calb.mult_round); |
| vpu_info("\t\t\t" "const_in1 : %d\n", pu[k].params.calb.const_in1); |
| vpu_info("\t\t\t" "div_shift_bits : %d\n", pu[k].params.calb.div_shift_bits); |
| vpu_info("\t\t\t" "div_overflow_remainder : %d\n", pu[k].params.calb.div_overflow_remainder); |
| vpu_info("\t\t\t" "thresh_lo : %d\n", pu[k].params.calb.thresh_lo); |
| vpu_info("\t\t\t" "thresh_hi : %d\n", pu[k].params.calb.thresh_hi); |
| vpu_info("\t\t\t" "val_lo : %d\n", pu[k].params.calb.val_lo); |
| vpu_info("\t\t\t" "val_hi : %d\n", pu[k].params.calb.val_hi); |
| vpu_info("\t\t\t" "val_med_filler : %d\n", pu[k].params.calb.val_med_filler); |
| break; |
| case VPUL_OP_ROI: |
| vpu_info("\t\t\t" "bits_in0 : %d\n", pu[k].params.rois_out.bits_in0); |
| vpu_info("\t\t\t" "signed_in0 : %d\n", pu[k].params.rois_out.signed_in0); |
| vpu_info("\t\t\t" "use_mask : %d\n", pu[k].params.rois_out.use_mask); |
| vpu_info("\t\t\t" "work_mode : %d\n", pu[k].params.rois_out.work_mode); |
| vpu_info("\t\t\t" "first_min_max : %d\n", pu[k].params.rois_out.first_min_max); |
| vpu_info("\t\t\t" "thresh_lo_temp : %d\n", pu[k].params.rois_out.thresh_lo_temp); |
| break; |
| case VPUL_OP_CROP: |
| vpu_info("\t\t\t" "work_mode : %d\n", pu[k].params.crop.work_mode); |
| vpu_info("\t\t\t" "pad_value : %d\n", pu[k].params.crop.pad_value); |
| vpu_info("\t\t\t" "mask_val_in : %d\n", pu[k].params.crop.mask_val_in); |
| vpu_info("\t\t\t" "mask_val_out : %d\n", pu[k].params.crop.mask_val_out); |
| vpu_info("\t\t\t" "roi_startx : %d\n", pu[k].params.crop.roi_startx); |
| vpu_info("\t\t\t" "roi_starty : %d\n", pu[k].params.crop.roi_starty); |
| break; |
| case VPUL_OP_MDE: |
| vpu_info("\t\t\t" "work_mode : %d\n", pu[k].params.mde.work_mode); |
| vpu_info("\t\t\t" "result_shift : %d\n", pu[k].params.mde.result_shift); |
| vpu_info("\t\t\t" "use_thresh : %d\n", pu[k].params.mde.use_thresh); |
| vpu_info("\t\t\t" "calc_quantized_angle : %d\n", pu[k].params.mde.calc_quantized_angle); |
| vpu_info("\t\t\t" "eig_coeff : %d\n", pu[k].params.mde.eig_coeff); |
| vpu_info("\t\t\t" "bits_in : %d\n", pu[k].params.mde.bits_in); |
| vpu_info("\t\t\t" "signed_in : %d\n", pu[k].params.mde.signed_in); |
| vpu_info("\t\t\t" "bits_out : %d\n", pu[k].params.mde.bits_out); |
| vpu_info("\t\t\t" "signed_out : %d\n", pu[k].params.mde.signed_out); |
| vpu_info("\t\t\t" "output_enable : %d\n", pu[k].params.mde.output_enable); |
| vpu_info("\t\t\t" "thresh : %d\n", pu[k].params.mde.thresh); |
| break; |
| case VPUL_OP_NMS: |
| vpu_info("\t\t\t" "work_mode : %d\n", pu[k].params.nms.work_mode); |
| vpu_info("\t\t\t" "keep_equals : %d\n", pu[k].params.nms.keep_equals); |
| vpu_info("\t\t\t" "directional_nms : %d\n", pu[k].params.nms.directional_nms); |
| vpu_info("\t\t\t" "census_mode : %d\n", pu[k].params.nms.census_mode); |
| vpu_info("\t\t\t" "add_orig_pixel : %d\n", pu[k].params.nms.add_orig_pixel); |
| vpu_info("\t\t\t" "bits_in : %d\n", pu[k].params.nms.bits_in); |
| vpu_info("\t\t\t" "bits_out : %d\n", pu[k].params.nms.bits_out); |
| vpu_info("\t\t\t" "signed_in : %d\n", pu[k].params.nms.signed_in); |
| vpu_info("\t\t\t" "support : %d\n", pu[k].params.nms.support); |
| vpu_info("\t\t\t" "org_val_out : %d\n", pu[k].params.nms.org_val_out); |
| vpu_info("\t\t\t" "trunc_out : %d\n", pu[k].params.nms.trunc_out); |
| vpu_info("\t\t\t" "image_height : %d\n", pu[k].params.nms.image_height); |
| vpu_info("\t\t\t" "thresh : %d\n", pu[k].params.nms.thresh); |
| vpu_info("\t\t\t" "border_mode_up : %d\n", pu[k].params.nms.border_mode_up); |
| vpu_info("\t\t\t" "border_mode_down : %d\n", pu[k].params.nms.border_mode_down); |
| vpu_info("\t\t\t" "border_mode_left : %d\n", pu[k].params.nms.border_mode_left); |
| vpu_info("\t\t\t" "border_mode_right : %d\n", pu[k].params.nms.border_mode_right); |
| vpu_info("\t\t\t" "border_fill : %d\n", pu[k].params.nms.border_fill); |
| vpu_info("\t\t\t" "border_fill_constant : %d\n", pu[k].params.nms.border_fill_constant); |
| vpu_info("\t\t\t" "strict_comparison_mask : %d\n", pu[k].params.nms.strict_comparison_mask); |
| vpu_info("\t\t\t" "cens_thres_0 : %d\n", pu[k].params.nms.cens_thres_0); |
| vpu_info("\t\t\t" "cens_thres_1 : %d\n", pu[k].params.nms.cens_thres_1); |
| vpu_info("\t\t\t" "cens_thres_2 : %d\n", pu[k].params.nms.cens_thres_2); |
| vpu_info("\t\t\t" "cens_thres_3 : %d\n", pu[k].params.nms.cens_thres_3); |
| vpu_info("\t\t\t" "cens_thres_4 : %d\n", pu[k].params.nms.cens_thres_4); |
| vpu_info("\t\t\t" "cens_thres_5 : %d\n", pu[k].params.nms.cens_thres_5); |
| vpu_info("\t\t\t" "cens_thres_6 : %d\n", pu[k].params.nms.cens_thres_6); |
| vpu_info("\t\t\t" "cens_thres_7 : %d\n", pu[k].params.nms.cens_thres_7); |
| break; |
| case VPUL_OP_CCM: |
| vpu_info("\t\t\t" "signed_in : %d\n", pu[k].params.ccm.signed_in); |
| vpu_info("\t\t\t" "signed_out : %d\n", pu[k].params.ccm.signed_out); |
| vpu_info("\t\t\t" "output_enable : %d\n", pu[k].params.ccm.output_enable); |
| vpu_info("\t\t\t" "input_enable : %d\n", pu[k].params.ccm.input_enable); |
| vpu_info("\t\t\t" "coefficient_shift : %d\n", pu[k].params.ccm.coefficient_shift); |
| vpu_info("\t\t\t" "coefficient_0 : %d\n", pu[k].params.ccm.coefficient_0); |
| vpu_info("\t\t\t" "coefficient_1 : %d\n", pu[k].params.ccm.coefficient_1); |
| vpu_info("\t\t\t" "coefficient_2 : %d\n", pu[k].params.ccm.coefficient_2); |
| vpu_info("\t\t\t" "coefficient_3 : %d\n", pu[k].params.ccm.coefficient_3); |
| vpu_info("\t\t\t" "coefficient_4 : %d\n", pu[k].params.ccm.coefficient_4); |
| vpu_info("\t\t\t" "coefficient_5 : %d\n", pu[k].params.ccm.coefficient_5); |
| vpu_info("\t\t\t" "coefficient_6 : %d\n", pu[k].params.ccm.coefficient_6); |
| vpu_info("\t\t\t" "coefficient_7 : %d\n", pu[k].params.ccm.coefficient_7); |
| vpu_info("\t\t\t" "coefficient_8 : %d\n", pu[k].params.ccm.coefficient_8); |
| vpu_info("\t\t\t" "offset_0 : %d\n", pu[k].params.ccm.offset_0); |
| vpu_info("\t\t\t" "offset_1 : %d\n", pu[k].params.ccm.offset_1); |
| vpu_info("\t\t\t" "offset_2 : %d\n", pu[k].params.ccm.offset_2); |
| break; |
| case VPUL_OP_SEP_FLT: |
| vpu_info("\t\t\t" "invert_columns : %d\n", pu[k].params.slf.invert_columns); |
| vpu_info("\t\t\t" "upsample_mode : %d\n", pu[k].params.slf.upsample_mode); |
| vpu_info("\t\t\t" "downsample_rows : %d\n", pu[k].params.slf.downsample_rows); |
| vpu_info("\t\t\t" "downsample_cols : %d\n", pu[k].params.slf.downsample_cols); |
| vpu_info("\t\t\t" "sampling_offset_x : %d\n", pu[k].params.slf.sampling_offset_x); |
| vpu_info("\t\t\t" "sampling_offset_y : %d\n", pu[k].params.slf.sampling_offset_y); |
| vpu_info("\t\t\t" "work_mode : %d\n", pu[k].params.slf.work_mode); |
| vpu_info("\t\t\t" "filter_size_mode : %d\n", pu[k].params.slf.filter_size_mode); |
| vpu_info("\t\t\t" "out_enable_1 : %d\n", pu[k].params.slf.out_enable_1); |
| vpu_info("\t\t\t" "horizontal_only : %d\n", pu[k].params.slf.horizontal_only); |
| vpu_info("\t\t\t" "bits_in : %d\n", pu[k].params.slf.bits_in); |
| vpu_info("\t\t\t" "bits_out : %d\n", pu[k].params.slf.bits_out); |
| vpu_info("\t\t\t" "signed_in : %d\n", pu[k].params.slf.signed_in); |
| vpu_info("\t\t\t" "signed_out : %d\n", pu[k].params.slf.signed_out); |
| vpu_info("\t\t\t" "do_rounding : %d\n", pu[k].params.slf.do_rounding); |
| vpu_info("\t\t\t" "border_mode_up : %d\n", pu[k].params.slf.border_mode_up); |
| vpu_info("\t\t\t" "border_mode_down : %d\n", pu[k].params.slf.border_mode_down); |
| vpu_info("\t\t\t" "border_mode_left : %d\n", pu[k].params.slf.border_mode_left); |
| vpu_info("\t\t\t" "border_mode_right : %d\n", pu[k].params.slf.border_mode_right); |
| vpu_info("\t\t\t" "border_fill : %d\n", pu[k].params.slf.border_fill); |
| vpu_info("\t\t\t" "border_fill_constant : %d\n", pu[k].params.slf.border_fill_constant); |
| vpu_info("\t\t\t" "coefficient_fraction : %d\n", pu[k].params.slf.coefficient_fraction); |
| vpu_info("\t\t\t" "sepfregs_is_max_pooling_mode : %d\n", pu[k].params.slf.sepfregs_is_max_pooling_mode); |
| vpu_info("\t\t\t" "sepfregs_stride_value : %d\n", pu[k].params.slf.sepfregs_stride_value); |
| vpu_info("\t\t\t" "sepfregs_stride_offset_height : %d\n", pu[k].params.slf.sepfregs_stride_offset_height); |
| vpu_info("\t\t\t" "sepfregs_stride_offset_width : %d\n", pu[k].params.slf.sepfregs_stride_offset_width); |
| vpu_info("\t\t\t" "sepfregs_subimage_height : %d\n", pu[k].params.slf.sepfregs_subimage_height); |
| vpu_info("\t\t\t" "sepfregs_convert_16f_to_32f : %d\n", pu[k].params.slf.sepfregs_convert_16f_to_32f); |
| vpu_info("\t\t\t" "sepfregs_convert_output_sm_to_2scomp : %d\n", pu[k].params.slf.sepfregs_convert_output_sm_to_2scomp); |
| vpu_info("\t\t\t" "sepfregs_convert_input_2scomp_to_sm : %d\n", pu[k].params.slf.sepfregs_convert_input_2scomp_to_sm); |
| vpu_info("\t\t\t" "maxp_num_slices : %d\n", pu[k].params.slf.maxp_num_slices); |
| vpu_info("\t\t\t" "maxp_sizes_filt_hor : %d\n", pu[k].params.slf.maxp_sizes_filt_hor); |
| vpu_info("\t\t\t" "maxp_sizes_filt_ver : %d\n", pu[k].params.slf.maxp_sizes_filt_ver); |
| vpu_info("\t\t\t" "coefficient_index : %d\n", pu[k].params.slf.coefficient_index); |
| break; |
| case VPUL_OP_GEN_FLT: |
| vpu_info("\t\t\t" "filter_size_mode : %d\n", pu[k].params.glf.filter_size_mode); |
| vpu_info("\t\t\t" "sad_mode : %d\n", pu[k].params.glf.sad_mode); |
| vpu_info("\t\t\t" "out_enable_2 : %d\n", pu[k].params.glf.out_enable_2); |
| vpu_info("\t\t\t" "two_outputs : %d\n", pu[k].params.glf.two_outputs); |
| vpu_info("\t\t\t" "input_enable1 : %d\n", pu[k].params.glf.input_enable1); |
| vpu_info("\t\t\t" "bits_in : %d\n", pu[k].params.glf.bits_in); |
| vpu_info("\t\t\t" "bits_out : %d\n", pu[k].params.glf.bits_out); |
| vpu_info("\t\t\t" "signed_in : %d\n", pu[k].params.glf.signed_in); |
| vpu_info("\t\t\t" "signed_out : %d\n", pu[k].params.glf.signed_out); |
| vpu_info("\t\t\t" "do_rounding : %d\n", pu[k].params.glf.do_rounding); |
| vpu_info("\t\t\t" "RAM_type : %d\n", pu[k].params.glf.RAM_type); |
| vpu_info("\t\t\t" "RAM_offset : %d\n", pu[k].params.glf.RAM_offset); |
| vpu_info("\t\t\t" "image_height : %d\n", pu[k].params.glf.image_height); |
| vpu_info("\t\t\t" "border_mode_up : %d\n", pu[k].params.glf.border_mode_up); |
| vpu_info("\t\t\t" "border_mode_down : %d\n", pu[k].params.glf.border_mode_down); |
| vpu_info("\t\t\t" "border_mode_left : %d\n", pu[k].params.glf.border_mode_left); |
| vpu_info("\t\t\t" "border_mode_right : %d\n", pu[k].params.glf.border_mode_right); |
| vpu_info("\t\t\t" "border_fill : %d\n", pu[k].params.glf.border_fill); |
| vpu_info("\t\t\t" "border_fill_constant : %d\n", pu[k].params.glf.border_fill_constant); |
| vpu_info("\t\t\t" "coefficient_fraction : %d\n", pu[k].params.glf.coefficient_fraction); |
| vpu_info("\t\t\t" "signed_coefficients : %d\n", pu[k].params.glf.signed_coefficients); |
| vpu_info("\t\t\t" "coefficient_index : %d\n", pu[k].params.glf.coefficient_index); |
| vpu_info("\t\t\t" "coeffs_from_dma : %d\n", pu[k].params.glf.coeffs_from_dma); |
| break; |
| case VPUL_OP_NLF_FLT: |
| vpu_info("\t\t\t" "filter_mode : %d\n", pu[k].params.nlf.filter_mode); |
| vpu_info("\t\t\t" "fast_score_direction : %d\n", pu[k].params.nlf.fast_score_direction); |
| vpu_info("\t\t\t" "border_mode_up : %d\n", pu[k].params.nlf.border_mode_up); |
| vpu_info("\t\t\t" "border_mode_left: %d\n", pu[k].params.nlf.border_mode_left); |
| vpu_info("\t\t\t" "border_mode_right : %d\n", pu[k].params.nlf.border_mode_right); |
| vpu_info("\t\t\t" "border_fill : %d\n", pu[k].params.nlf.border_fill); |
| vpu_info("\t\t\t" "border_tile : %d\n", pu[k].params.nlf.border_tile); |
| vpu_info("\t\t\t" "border_fill_constant : %d\n", pu[k].params.nlf.border_fill_constant); |
| vpu_info("\t\t\t" "bits_in : %d\n", pu[k].params.nlf.bits_in); |
| vpu_info("\t\t\t" "signed_in : %d\n", pu[k].params.nlf.signed_in); |
| vpu_info("\t\t\t" "census_mode : %d\n", pu[k].params.nlf.census_mode); |
| vpu_info("\t\t\t" "census_out_image : %d\n", pu[k].params.nlf.census_out_image); |
| vpu_info("\t\t\t" "add_orig_pixel : %d\n", pu[k].params.nlf.add_orig_pixel); |
| vpu_info("\t\t\t" "cens_thres_0 : %d\n", pu[k].params.nlf.cens_thres_0); |
| vpu_info("\t\t\t" "cens_thres_1 : %d\n", pu[k].params.nlf.cens_thres_1); |
| vpu_info("\t\t\t" "cens_thres_2 : %d\n", pu[k].params.nlf.cens_thres_2); |
| vpu_info("\t\t\t" "cens_thres_3 : %d\n", pu[k].params.nlf.cens_thres_3); |
| vpu_info("\t\t\t" "cens_thres_4 : %d\n", pu[k].params.nlf.cens_thres_4); |
| vpu_info("\t\t\t" "cens_thres_5 : %d\n", pu[k].params.nlf.cens_thres_5); |
| vpu_info("\t\t\t" "cens_thres_6 : %d\n", pu[k].params.nlf.cens_thres_6); |
| vpu_info("\t\t\t" "cens_thres_7 : %d\n", pu[k].params.nlf.cens_thres_7); |
| vpu_info("\t\t\t" "neighbors_mask : %d\n", pu[k].params.nlf.neighbors_mask); |
| break; |
| case VPUL_OP_UPSCALER: |
| vpu_info("\t\t\t" "interpolation_method : %d\n", pu[k].params.upscaler.interpolation_method); |
| vpu_info("\t\t\t" "border_fill_mode : %d\n", pu[k].params.upscaler.border_fill_mode); |
| vpu_info("\t\t\t" "do_rounding : %d\n", pu[k].params.upscaler.do_rounding); |
| vpu_info("\t\t\t" "border_fill_constant : %d\n", pu[k].params.upscaler.border_fill_constant); |
| break; |
| case VPUL_OP_DOWNSCALER: |
| vpu_info("\t\t\t" "interpolation_method : %d\n", pu[k].params.downScaler.interpolation_method); |
| vpu_info("\t\t\t" "do_rounding : %d\n", pu[k].params.downScaler.do_rounding); |
| break; |
| case VPUL_OP_DUPLICATE: |
| break; |
| case VPUL_OP_SPLIT: |
| vpu_info("\t\t\t" "out0_byte0 : %d\n", pu[k].params.spliter.out0_byte0); |
| vpu_info("\t\t\t" "out0_byte1 : %d\n", pu[k].params.spliter.out0_byte1); |
| vpu_info("\t\t\t" "out1_byte0 : %d\n", pu[k].params.spliter.out1_byte0); |
| vpu_info("\t\t\t" "out1_byte1 : %d\n", pu[k].params.spliter.out1_byte1); |
| vpu_info("\t\t\t" "out2_byte0 : %d\n", pu[k].params.spliter.out2_byte0); |
| vpu_info("\t\t\t" "out2_byte1 : %d\n", pu[k].params.spliter.out2_byte1); |
| vpu_info("\t\t\t" "out3_byte0 : %d\n", pu[k].params.spliter.out3_byte0); |
| vpu_info("\t\t\t" "out3_byte1 : %d\n", pu[k].params.spliter.out3_byte1); |
| break; |
| case VPUL_OP_JOIN: |
| vpu_info("\t\t\t" "out_byte0_source_stream : %d\n", pu[k].params.joiner.out_byte0_source_stream); |
| vpu_info("\t\t\t" "out_byte1_source_stream : %d\n", pu[k].params.joiner.out_byte1_source_stream); |
| vpu_info("\t\t\t" "out_byte2_source_stream : %d\n", pu[k].params.joiner.out_byte2_source_stream); |
| vpu_info("\t\t\t" "out_byte3_source_stream : %d\n", pu[k].params.joiner.out_byte3_source_stream); |
| vpu_info("\t\t\t" "input0_enable : %d\n", pu[k].params.joiner.input0_enable); |
| vpu_info("\t\t\t" "input1_enable : %d\n", pu[k].params.joiner.input1_enable); |
| vpu_info("\t\t\t" "input2_enable : %d\n", pu[k].params.joiner.input2_enable); |
| vpu_info("\t\t\t" "input3_enable : %d\n", pu[k].params.joiner.input3_enable); |
| vpu_info("\t\t\t" "work_mode : %d\n", pu[k].params.joiner.work_mode); |
| break; |
| case VPUL_OP_INTEGRAL_IMG: |
| vpu_info("\t\t\t" "integral_image_mode : %d\n", pu[k].params.integral.integral_image_mode); |
| vpu_info("\t\t\t" "overflow_mode : %d\n", pu[k].params.integral.overflow_mode); |
| vpu_info("\t\t\t" "dt_right_shift : %d\n", pu[k].params.integral.dt_right_shift); |
| vpu_info("\t\t\t" "dt_left_shift : %d\n", pu[k].params.integral.dt_left_shift); |
| vpu_info("\t\t\t" "dt_coefficient0 : %d\n", pu[k].params.integral.dt_coefficient0); |
| vpu_info("\t\t\t" "dt_coefficient1 : %d\n", pu[k].params.integral.dt_coefficient1); |
| vpu_info("\t\t\t" "dt_coefficient2 : %d\n", pu[k].params.integral.dt_coefficient2); |
| vpu_info("\t\t\t" "cc_min_label : %d\n", pu[k].params.integral.cc_min_label); |
| vpu_info("\t\t\t" "cc_scan_mode : %d\n", pu[k].params.integral.cc_scan_mode); |
| vpu_info("\t\t\t" "cc_smart_label_search_en : %d\n", pu[k].params.integral.cc_smart_label_search_en); |
| vpu_info("\t\t\t" "cc_reset_labels_array : %d\n", pu[k].params.integral.cc_reset_labels_array); |
| vpu_info("\t\t\t" "cc_label_vector_size : %d\n", pu[k].params.integral.cc_label_vector_size); |
| vpu_info("\t\t\t" "lut_init_en : %d\n", pu[k].params.integral.lut_init_en); |
| vpu_info("\t\t\t" "lut_number_of_values : %d\n", pu[k].params.integral.lut_number_of_values); |
| vpu_info("\t\t\t" "lut_value_shift : %d\n", pu[k].params.integral.lut_value_shift); |
| vpu_info("\t\t\t" "lut_default_overflow : %d\n", pu[k].params.integral.lut_default_overflow); |
| vpu_info("\t\t\t" "lut_default_underflow : %d\n", pu[k].params.integral.lut_default_underflow); |
| break; |
| case VPUL_OP_MAP_2_LST: |
| vpu_info("\t\t\t" "bits_in : %d\n", pu[k].params.map2list.bits_in); |
| vpu_info("\t\t\t" "signed_in : %d\n", pu[k].params.map2list.signed_in); |
| vpu_info("\t\t\t" "value_in : %d\n", pu[k].params.map2list.value_in); |
| vpu_info("\t\t\t" "enable_out_map : %d\n", pu[k].params.map2list.enable_out_map); |
| vpu_info("\t\t\t" "enable_out_lst : %d\n", pu[k].params.map2list.enable_out_lst); |
| vpu_info("\t\t\t" "inout_indx : %d\n", pu[k].params.map2list.inout_indx); |
| vpu_info("\t\t\t" "threshold_low : %d\n", pu[k].params.map2list.threshold_low); |
| vpu_info("\t\t\t" "threshold_high : %d\n", pu[k].params.map2list.threshold_high); |
| vpu_info("\t\t\t" "num_of_point : %d\n", pu[k].params.map2list.num_of_point); |
| break; |
| case VPUL_OP_FIFO: |
| break; |
| case VPUL_OP_CNN: |
| break; |
| case VPUL_OP_LUT: |
| vpu_info("\t\t\t" "interpolation_mode : %d\n", pu[k].params.lut.interpolation_mode); |
| vpu_info("\t\t\t" "lut_size : %d\n", pu[k].params.lut.lut_size); |
| vpu_info("\t\t\t" "signed_in0 : %d\n", pu[k].params.lut.signed_in0); |
| vpu_info("\t\t\t" "signed_out0 : %d\n", pu[k].params.lut.signed_out0); |
| vpu_info("\t\t\t" "offset : %d\n", pu[k].params.lut.offset); |
| vpu_info("\t\t\t" "binsize : %d\n", pu[k].params.lut.binsize); |
| vpu_info("\t\t\t" "inverse_binsize : %d\n", pu[k].params.lut.inverse_binsize); |
| break; |
| case VPUL_OP_HIST: |
| vpu_info("\t\t\t" "offset : %d\n", pu[k].params.histogram.offset); |
| vpu_info("\t\t\t" "inverse_binsize : %d\n", pu[k].params.histogram.inverse_binsize); |
| vpu_info("\t\t\t" "variable_increment : %d\n", pu[k].params.histogram.variable_increment); |
| vpu_info("\t\t\t" "dual_histogram : %d\n", pu[k].params.histogram.dual_histogram); |
| vpu_info("\t\t\t" "signed_in0 : %d\n", pu[k].params.histogram.signed_in0); |
| vpu_info("\t\t\t" "round_index : %d\n", pu[k].params.histogram.round_index); |
| vpu_info("\t\t\t" "max_val : %d\n", pu[k].params.histogram.max_val); |
| break; |
| default: |
| break; |
| } |
| } |
| } else if (subchain[j].stype == VPUL_SUB_CH_CPU_OP) { |
| for (k = 0; k < MAX_SUPPORT_CPU_OPER_NUM; ++k) { |
| vpu_info("\t\t\t" "[CPU:%d]\n", k); |
| vpu_info("\t\t\t" "opcode : %d\n", subchain[j].cpu.cpu_op_desc[k].opcode); |
| } |
| } |
| } |
| } |
| } |
| |
| void vpu_graph_print(struct vpu_graph *graph) |
| { |
| u32 i; |
| struct vpu_framemgr *framemgr; |
| struct vpu_exynos *exynos; |
| |
| BUG_ON(!graph); |
| |
| exynos = graph->exynos; |
| framemgr = &graph->framemgr; |
| |
| vpu_info("GRAPH[%02d]: %2d %2d %2d %2d %2d\n", graph->id, |
| framemgr->fre_cnt, |
| framemgr->pre_cnt, |
| framemgr->req_cnt, |
| framemgr->pro_cnt, |
| framemgr->com_cnt); |
| |
| for (i = 0; i < VPU_PU_NUMBER; ++i) { |
| if (graph->pu_map[i]) { |
| CTL_OP(exynos, ctl_dump, i); |
| } |
| } |
| } |
| |
| struct vpuo_chain * vpu_graph_g_chain(struct vpu_graph *graph, u32 chain_id) |
| { |
| int i, j; |
| struct vpuo_vertex *vertex; |
| struct vpuo_chain *chain = NULL; |
| |
| for (i = 0; i < graph->vertex_cnt; ++i) { |
| vertex = graph->vertex_array[i]; |
| if (!vertex) { |
| vpu_ierr("vertex is NULL\n", graph); |
| BUG(); |
| } |
| |
| for (j = 0; j < vertex->chain_cnt; ++j) { |
| if (vertex->chain_table[j] == chain_id) { |
| chain = vertex->chain_array[j]; |
| break; |
| } |
| } |
| } |
| |
| return chain; |
| } |
| |
| int vpu_graph_create(struct vpu_graph **graph, void *cookie, void *resource, void *memory, void *exynos) |
| { |
| int ret = 0; |
| u32 i; |
| struct vpu_framemgr *framemgr; |
| |
| BUG_ON(!*graph); |
| BUG_ON(!cookie); |
| |
| *graph = kzalloc(sizeof(struct vpu_graph), GFP_KERNEL); |
| if (*graph == NULL) { |
| vpu_err("kzalloc is fail"); |
| ret = -ENOMEM; |
| goto p_err; |
| } |
| |
| ret = vpu_graphmgr_grp_register(cookie, *graph); |
| if (ret) { |
| vpu_err("vpu_graphmgr_grp_register is fail(%d)\n", ret); |
| kfree(*graph); |
| goto p_err; |
| } |
| |
| (*graph)->control.message = VPU_CTRL_NONE; |
| (*graph)->cookie = cookie; |
| (*graph)->resource = resource; |
| (*graph)->memory = memory; |
| (*graph)->exynos = exynos; |
| (*graph)->gops = &vpu_graph_ops; |
| mutex_init(&(*graph)->local_lock); |
| |
| /* frame manager init */ |
| framemgr = &(*graph)->framemgr; |
| framemgr->id = (*graph)->id; |
| framemgr->sindex = 0; |
| spin_lock_init(&framemgr->slock); |
| |
| for (i = 0; i < VPU_MAX_FRAME; ++i) { |
| (*graph)->inhash[i] = VPU_MAX_FRAME; |
| (*graph)->othash[i] = VPU_MAX_FRAME; |
| } |
| |
| (*graph)->control.owner = *graph; |
| init_waitqueue_head(&(*graph)->control_wq); |
| ret = vpu_frame_init(framemgr, *graph); |
| if (ret) { |
| vpu_err("vpu_frame_init is fail(%d)\n", ret); |
| kfree(*graph); |
| goto p_err; |
| } |
| |
| p_err: |
| return ret; |
| } |
| |
| int vpu_graph_destroy(struct vpu_graph *graph) |
| { |
| int ret = 0; |
| |
| BUG_ON(!graph); |
| |
| ret = __vpu_graph_stop(graph); |
| if (ret) |
| vpu_ierr("__vpu_graph_stop is fail(%d)\n", graph, ret); |
| |
| ret = vpu_graphmgr_grp_unregister(graph->cookie, graph); |
| if (ret) |
| vpu_ierr("vpu_graphmgr_grp_unregister is fail(%d)\n", graph, ret); |
| |
| ret = __vpu_graph_unmap(graph); |
| if (ret) |
| vpu_ierr("__vpu_graph_map is fail(%d)\n", graph, ret); |
| |
| ret = __vpu_graph_free(graph); |
| if (ret) |
| vpu_ierr("__vpu_graph_free is fail(%d)\n", graph, ret); |
| |
| kfree(graph->desc_utask); |
| kfree(graph->desc_mtask); |
| kfree(graph); |
| |
| return ret; |
| } |
| |
| int vpu_graph_config(struct vpu_graph *graph, struct vs4l_graph *info) |
| { |
| int ret = 0; |
| |
| BUG_ON(!graph); |
| BUG_ON(!graph->cookie); |
| BUG_ON(!info); |
| |
| if (test_bit(VPU_GRAPH_STATE_CONFIG, &graph->state)) { |
| vpu_ierr("graph is already configured\n", graph); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| if (info->priority > VPU_GRAPH_MAX_PRIORITY) { |
| vpu_iwarn("graph priority is over(%d)\n", graph, info->priority); |
| info->priority = VPU_GRAPH_MAX_PRIORITY; |
| } |
| |
| graph->uid = info->id; |
| graph->flags = info->flags; |
| graph->priority = info->priority; |
| graph->size = info->size; |
| graph->period_ticks = 0; |
| graph->desc_utask = NULL; |
| graph->desc_mtask = NULL; |
| |
| if (test_bit(VS4L_GRAPH_FLAG_PERIODIC, &graph->flags)) |
| graph->period_ticks = info->time >= VPU_TIME_TICK ? info->time / VPU_TIME_TICK : 1; |
| |
| /* 1. memory allocation */ |
| if (!graph->size) { |
| vpu_ierr("task descriptor size is zero(%lX %d)\n", graph, info->addr, info->size); |
| ret = -ENOMEM; |
| goto p_err; |
| } |
| |
| graph->desc_utask = kzalloc(graph->size, GFP_KERNEL); |
| if (!graph->desc_utask) { |
| vpu_ierr("kzalloc(desc_utask) is fail\n", graph); |
| ret = -ENOMEM; |
| goto p_err; |
| } |
| |
| graph->desc_mtask = kzalloc(graph->size, GFP_KERNEL); |
| if (!graph->desc_mtask) { |
| vpu_ierr("kzalloc(desc_mtask) is fail\n", graph); |
| ret = -ENOMEM; |
| goto p_err; |
| } |
| |
| ret = copy_from_user(graph->desc_utask, (void *)info->addr, graph->size); |
| if (ret) { |
| vpu_ierr("copy_from_user is fail(%d)\n", graph, ret); |
| goto p_err; |
| } |
| |
| if (info->id != graph->desc_utask->id) { |
| vpu_iwarn("gid(%d) is not same with tid(%d)\n", graph, |
| info->id, graph->desc_utask->id); |
| graph->desc_utask->id = info->id; |
| } |
| |
| memcpy(graph->desc_mtask, graph->desc_utask, graph->size); |
| |
| #ifdef DBG_PRINT_TASK |
| vpu_graph_task_print(graph); |
| #endif |
| |
| /* 2. graph allocation */ |
| ret = __vpu_graph_alloc(graph); |
| if (ret) { |
| vpu_ierr("__vpu_graph_alloc is fail(%d)\n", graph, ret); |
| goto p_err; |
| } |
| |
| /* 3. parsing */ |
| ret = __vpu_graph_parse(graph); |
| if (ret) { |
| vpu_ierr("__vpu_graph_parse is fail(%d)\n", graph, ret); |
| goto p_err; |
| } |
| |
| /* 4. Buffer Mapping */ |
| ret = __vpu_graph_map(graph); |
| if (ret) { |
| vpu_ierr("__vpu_graph_map is fail(%d)\n", graph, ret); |
| goto p_err; |
| } |
| |
| set_bit(VPU_GRAPH_STATE_CONFIG, &graph->state); |
| |
| p_err: |
| vpu_iinfo("%s(%d, %d, %X):%d\n", graph, __func__, info->id, info->priority, info->flags, ret); |
| return ret; |
| } |
| |
| int vpu_graph_param(struct vpu_graph *graph, struct vs4l_param_list *plist) |
| { |
| int ret = 0; |
| struct vs4l_param *param; |
| struct vpuo_pu *pu; |
| char *pu_base; |
| u32 i; |
| |
| if (!graph->update_cnt) { |
| ret = -EINVAL; |
| vpu_ierr("update_cnt is zero\n", graph); |
| goto p_err; |
| } |
| |
| for (i = 0; i < plist->count; ++i) { |
| param = &plist->params[i]; |
| |
| pu = __vpu_graph_find_pu(graph, param->target); |
| if (!pu) { |
| vpu_ierr("__vpu_graph_find_pu is fail(0x%X)\n", graph, param->target); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| if (!pu->desc_mpu) { |
| vpu_ierr("desc_mpu is NULL\n", graph); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| pu_base = (char *)&pu->desc_mpu->params; |
| ret = copy_from_user(pu_base + param->offset, (void *)param->addr, param->size); |
| if (ret) { |
| vpu_ierr("copy_from_user() is fail(%d)\n", graph, ret); |
| goto p_err; |
| } |
| } |
| |
| set_bit(VPU_GRAPH_FLAG_UPDATE_PARAM, &graph->flags); |
| |
| p_err: |
| return ret; |
| } |
| |
| static int vpu_graph_prepare(struct vb_queue *q, struct vb_container_list *clist) |
| { |
| int ret = 0; |
| u32 i, target; |
| struct vpu_queue *queue = q->private_data; |
| struct vpu_vertex_ctx *vctx; |
| struct list_head *list; |
| struct vpu_graph *graph; |
| struct vpuo_pu *pu; |
| |
| BUG_ON(!queue); |
| BUG_ON(!clist); |
| |
| vctx = container_of(queue, struct vpu_vertex_ctx, queue); |
| graph = container_of(vctx, struct vpu_graph, vctx); |
| |
| if (test_bit(VS4L_GRAPH_FLAG_PRIMITIVE, &graph->flags)) |
| return 0; |
| |
| if (clist->index >= VPU_MAX_BUFFER) { |
| vpu_ierr("clist index is invalid(%d)\n", graph, clist->index); |
| BUG(); |
| } |
| |
| if (clist->direction == VS4L_DIRECTION_IN) |
| list = &graph->inleaf_list; |
| else |
| list = &graph->otleaf_list; |
| |
| for (i = 0; i < clist->count; ++i) { |
| target = clist->containers[i].target; |
| |
| pu = __vpu_graph_find_iopu(list, target); |
| if (!pu) { |
| vpu_ierr("(%d) target(%d) is NULL\n", graph, clist->direction, target); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| if (pu->container[clist->index]) { |
| vpu_ierr("clist index is already prepared(%d)\n", graph, clist->index); |
| BUG(); |
| } |
| |
| pu->container[clist->index] = &clist->containers[i]; |
| } |
| |
| p_err: |
| vpu_iinfo("%s(%d):%d\n", graph, __func__, clist->index, ret); |
| return ret; |
| } |
| |
| static int vpu_graph_unprepare(struct vb_queue *q, struct vb_container_list *clist) |
| { |
| int ret = 0; |
| u32 i, target; |
| struct vpu_queue *queue = q->private_data; |
| struct vpu_vertex_ctx *vctx; |
| struct list_head *list; |
| struct vpu_graph *graph; |
| struct vpuo_pu *pu; |
| |
| BUG_ON(!queue); |
| BUG_ON(!clist); |
| |
| vctx = container_of(queue, struct vpu_vertex_ctx, queue); |
| graph = container_of(vctx, struct vpu_graph, vctx); |
| |
| if (test_bit(VS4L_GRAPH_FLAG_PRIMITIVE, &graph->flags)) |
| return 0; |
| |
| if (clist->index >= VPU_MAX_BUFFER) { |
| vpu_ierr("clist index is invalid(%d)\n", graph, clist->index); |
| BUG(); |
| } |
| |
| if (clist->direction == VS4L_DIRECTION_IN) |
| list = &graph->inleaf_list; |
| else |
| list = &graph->otleaf_list; |
| |
| for (i = 0; i < clist->count; ++i) { |
| target = clist->containers[i].target; |
| |
| pu = __vpu_graph_find_iopu(list, target); |
| if (!pu) { |
| vpu_ierr("(%d) target(%d) is NULL\n", graph, clist->direction, target); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| pu->container[clist->index] = NULL; |
| } |
| |
| p_err: |
| vpu_iinfo("%s(%d):%d\n", graph, __func__, clist->index, ret); |
| return ret; |
| } |
| |
| const struct vb_ops vb_ops = { |
| .buf_prepare = vpu_graph_prepare, |
| .buf_unprepare = vpu_graph_unprepare |
| }; |
| |
| int vpu_graph_start(struct vpu_queue *queue) |
| { |
| int ret = 0; |
| struct vpu_vertex_ctx *vctx; |
| struct vpu_graph *graph; |
| |
| BUG_ON(!queue); |
| |
| vctx = container_of(queue, struct vpu_vertex_ctx, queue); |
| graph = container_of(vctx, struct vpu_graph, vctx); |
| |
| ret = __vpu_graph_start(graph); |
| if (ret) |
| vpu_ierr("__vpu_graph_start is fail(%d)\n", graph, ret); |
| |
| vpu_iinfo("%s():%d\n", graph, __func__, ret); |
| return ret; |
| } |
| |
| int vpu_graph_stop(struct vpu_queue *queue) |
| { |
| int ret = 0; |
| struct vpu_graph *graph; |
| struct vpu_vertex_ctx *vctx; |
| |
| BUG_ON(!queue); |
| |
| vctx = container_of(queue, struct vpu_vertex_ctx, queue); |
| graph = container_of(vctx, struct vpu_graph, vctx); |
| |
| ret = __vpu_graph_stop(graph); |
| if (ret) |
| vpu_ierr("__vpu_graph_stop is fail(%d)\n", graph, ret); |
| |
| vpu_iinfo("%s():%d\n", graph, __func__, ret); |
| return 0; |
| } |
| |
| int vpu_graph_format(struct vpu_queue *queue, struct vs4l_format_list *flist) |
| { |
| int ret = 0; |
| u32 i, target; |
| char *fourcc; |
| struct vpu_vertex_ctx *vctx; |
| struct list_head *list; |
| struct vpu_graph *graph; |
| struct vpuo_chain *chain; |
| struct vpuo_pu *pu, *temp; |
| |
| BUG_ON(!queue); |
| BUG_ON(!flist); |
| |
| vctx = container_of(queue, struct vpu_vertex_ctx, queue); |
| graph = container_of(vctx, struct vpu_graph, vctx); |
| |
| if (test_bit(VS4L_GRAPH_FLAG_PRIMITIVE, &graph->flags)) |
| return 0; |
| |
| if (flist->direction == VS4L_DIRECTION_IN) |
| list = &graph->inleaf_list; |
| else |
| list = &graph->otleaf_list; |
| |
| for (i = 0; i < flist->count; ++i) { |
| target = flist->formats[i].target; |
| fourcc = (char *)&flist->formats[i].format; |
| |
| pu = __vpu_graph_find_iopu(list, target); |
| if (!pu) { |
| vpu_ierr("(%d) target(%d) is NULL\n", graph, flist->direction, target); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| chain = pu->parent; |
| if (!chain) { |
| vpu_ierr("(%d) chain(%d) is NULL\n", graph, flist->direction, target); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| vpu_iinfo("C%dP%d : %dx%d@%c%c%c%c\n", graph, |
| chain->id, pu->id, |
| flist->formats[i].width, |
| flist->formats[i].height, |
| fourcc[0], fourcc[1], fourcc[2], fourcc[3]); |
| |
| set_bit(VPUO_PU_STATE_FORMAT, &pu->state); |
| } |
| |
| list_for_each_entry_safe(pu, temp, list, gleaf_entry) { |
| if (!test_bit(VPUO_PU_STATE_FORMAT, &pu->state)) { |
| vpu_ierr("pu %d is not formatted\n", graph, pu->id); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| } |
| |
| p_err: |
| return ret; |
| } |
| |
| static int vpu_graph_queue(struct vpu_queue *queue, struct vb_container_list *incl, struct vb_container_list *otcl) |
| { |
| int ret = 0; |
| unsigned long flag; |
| struct vpu_graph *graph; |
| struct vpu_vertex_ctx *vctx; |
| struct vpu_framemgr *framemgr; |
| struct vpu_frame *frame; |
| struct vpuo_pu *pu, *temp; |
| struct list_head *list; |
| dma_addr_t dvaddr; |
| u32 i, j; |
| |
| BUG_ON(!queue); |
| BUG_ON(!incl); |
| BUG_ON(!incl->index >= VPU_MAX_FRAME); |
| BUG_ON(!otcl); |
| BUG_ON(!otcl->index >= VPU_MAX_FRAME); |
| |
| vctx = container_of(queue, struct vpu_vertex_ctx, queue); |
| graph = container_of(vctx, struct vpu_graph, vctx); |
| framemgr = &graph->framemgr; |
| |
| if (!test_bit(VPU_GRAPH_STATE_START, &graph->state)) { |
| vpu_ierr("graph is NOT start\n", graph); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| if (incl->id != otcl->id) { |
| vpu_warn("buffer id is incoincidence(%d, %d)\n", incl->id, otcl->id); |
| otcl->id = incl->id; |
| } |
| |
| framemgr_e_barrier_irqs(framemgr, 0, flag); |
| vpu_frame_pick_fre_to_req(framemgr, &frame); |
| framemgr_x_barrier_irqr(framemgr, 0, flag); |
| |
| if (!frame) { |
| vpu_ierr("frame is lack\n", graph); |
| vpu_frame_print_all(framemgr); |
| ret = -ENOMEM; |
| goto p_err; |
| } |
| |
| if (test_bit(VS4L_GRAPH_FLAG_PRIMITIVE, &graph->flags)) { |
| u32 index; |
| |
| if (graph->iobuffer_cnt != (incl->count + otcl->count)) { |
| vpu_ierr("iobuffer cnt is invalid(%d %d)\n", graph, incl->count, otcl->count); |
| BUG(); |
| } |
| |
| for (i = 0; i < incl->count; ++i) { |
| index = incl->containers[i].target & VS4L_TARGET_PU; |
| |
| for (j = 0; j < graph->iobuffer_cnt; ++j) { |
| if (index == graph->iobuffer_idx[j]) { |
| dvaddr = incl->containers[i].buffers[0].dvaddr; |
| if (dvaddr < VPU_AHB_BASE_ADDR) { |
| vpu_ierr("dvaddr is invalid(%pa)\n", graph, &dvaddr); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| graph->iobuffer_dat[j] = dvaddr - VPU_AHB_BASE_ADDR; |
| break; |
| } |
| } |
| |
| if (j >= graph->iobuffer_cnt) { |
| vpu_ierr("target %d is not found\n", graph, index); |
| BUG(); |
| } |
| } |
| |
| for (i = 0; i < otcl->count; ++i) { |
| index = otcl->containers[i].target & VS4L_TARGET_PU; |
| |
| for (j = 0; j < graph->iobuffer_cnt; ++j) { |
| if (index == graph->iobuffer_idx[j]) { |
| dvaddr = otcl->containers[i].buffers[0].dvaddr; |
| if (dvaddr < VPU_AHB_BASE_ADDR) { |
| vpu_ierr("dvaddr is invalid(%pa)\n", graph, &dvaddr); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| graph->iobuffer_dat[j] = dvaddr - VPU_AHB_BASE_ADDR; |
| break; |
| } |
| } |
| |
| if (j >= graph->iobuffer_cnt) { |
| vpu_ierr("target %d is not found\n", graph, index); |
| BUG(); |
| } |
| } |
| |
| goto p_skip_primitive; |
| } |
| |
| list = &graph->inleaf_list; |
| list_for_each_entry_safe(pu, temp, list, gleaf_entry) { |
| if (pu->container[incl->index]->type != VS4L_BUFFER_LIST) { |
| vpu_err("this buffer type is not supported\n"); |
| BUG(); |
| } |
| |
| for (i = 0; i < pu->container[incl->index]->count; ++i) { |
| dvaddr = pu->container[incl->index]->buffers[i].dvaddr; |
| if (dvaddr < VPU_AHB_BASE_ADDR) { |
| vpu_ierr("dvaddr is invalid(%pa)\n", graph, &dvaddr); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| if (!pu->buffer_ptr[i]) { |
| vpu_ierr("%d pu buffer is NULL\n", graph, pu->id); |
| BUG(); |
| } |
| |
| *pu->buffer_ptr[i] = dvaddr - VPU_AHB_BASE_ADDR; |
| } |
| } |
| |
| list = &graph->otleaf_list; |
| list_for_each_entry_safe(pu, temp, list, gleaf_entry) { |
| if (pu->container[otcl->index]->type != VS4L_BUFFER_LIST) { |
| vpu_err("this buffer type is not supported\n"); |
| BUG(); |
| } |
| |
| for (i = 0; i < pu->container[otcl->index]->count; ++i) { |
| dvaddr = pu->container[otcl->index]->buffers[i].dvaddr; |
| if (dvaddr < VPU_AHB_BASE_ADDR) { |
| vpu_ierr("dvaddr is invalid(%pa)\n", graph, &dvaddr); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| if (pu->type == VPUL_OP_ROI) { |
| set_bit(VPU_FRAME_FLAG_IOCPY, &frame->flags); |
| continue; |
| } |
| |
| if (!pu->buffer_ptr[i]) { |
| vpu_ierr("%d pu buffer is NULL\n", graph, pu->id); |
| BUG(); |
| } |
| |
| *pu->buffer_ptr[i] = dvaddr - VPU_AHB_BASE_ADDR; |
| } |
| } |
| |
| p_skip_primitive: |
| graph->inhash[incl->index] = frame->index; |
| graph->othash[otcl->index] = frame->index; |
| graph->input_cnt++; |
| |
| frame->id = incl->id; |
| frame->incl = incl; |
| frame->otcl = otcl; |
| frame->message = VPU_FRAME_REQUEST; |
| frame->param0 = 0; |
| frame->param1 = 0; |
| frame->param2 = 0; |
| frame->param3 = 0; |
| clear_bit(VS4L_CL_FLAG_TIMESTAMP, &frame->flags); |
| |
| if ((incl->flags & (1 << VS4L_CL_FLAG_TIMESTAMP)) || |
| (otcl->flags & (1 << VS4L_CL_FLAG_TIMESTAMP))) { |
| set_bit(VS4L_CL_FLAG_TIMESTAMP, &frame->flags); |
| vpu_get_timestamp(&frame->time[VPU_TMP_QUEUE]); |
| } |
| |
| vpu_graphmgr_queue(graph->cookie, frame); |
| |
| p_err: |
| return ret; |
| } |
| |
| static int vpu_graph_deque(struct vpu_queue *queue, struct vb_container_list *clist) |
| { |
| int ret = 0; |
| u32 findex; |
| unsigned long flags; |
| struct vpu_graph *graph; |
| struct vpu_vertex_ctx *vctx; |
| struct vpu_framemgr *framemgr; |
| struct vpu_frame *frame; |
| |
| BUG_ON(!queue); |
| BUG_ON(!clist); |
| BUG_ON(!clist->index >= VPU_MAX_FRAME); |
| |
| vctx = container_of(queue, struct vpu_vertex_ctx, queue); |
| graph = container_of(vctx, struct vpu_graph, vctx); |
| framemgr = &graph->framemgr; |
| |
| if (!test_bit(VPU_GRAPH_STATE_START, &graph->state)) { |
| vpu_ierr("graph is NOT start\n", graph); |
| ret = -EINVAL; |
| goto p_err; |
| } |
| |
| if (clist->direction == VS4L_DIRECTION_IN) |
| findex = graph->inhash[clist->index]; |
| else |
| findex = graph->othash[clist->index]; |
| |
| if (findex >= VPU_MAX_FRAME) { |
| vpu_ierr("frame index(%d) invalid\n", graph, findex); |
| BUG(); |
| } |
| |
| frame = &framemgr->frame[findex]; |
| if (frame->state != VPU_FRAME_STATE_COMPLETE) { |
| vpu_ierr("frame state(%d) is invalid\n", graph, frame->state); |
| BUG(); |
| } |
| |
| if (clist->direction == VS4L_DIRECTION_IN) { |
| if (frame->incl != clist) { |
| vpu_ierr("incl ptr is invalid(%p != %p)\n", graph, frame->incl, clist); |
| BUG(); |
| } |
| |
| graph->inhash[clist->index] = VPU_MAX_FRAME; |
| frame->incl = NULL; |
| } else { |
| if (frame->otcl != clist) { |
| vpu_ierr("otcl ptr is invalid(%p != %p)\n", graph, frame->otcl, clist); |
| BUG(); |
| } |
| |
| graph->othash[clist->index] = VPU_MAX_FRAME; |
| frame->otcl = NULL; |
| } |
| |
| if (frame->incl || frame->otcl) |
| goto p_err; |
| |
| framemgr_e_barrier_irqs(framemgr, 0, flags); |
| vpu_frame_trans_com_to_fre(framemgr, frame); |
| framemgr_x_barrier_irqr(framemgr, 0, flags); |
| |
| p_err: |
| return ret; |
| } |
| |
| const struct vpu_queue_ops vpu_queue_ops = { |
| .start = vpu_graph_start, |
| .stop = vpu_graph_stop, |
| .format = vpu_graph_format, |
| .queue = vpu_graph_queue, |
| .deque = vpu_graph_deque |
| }; |
| |
| static int vpu_graph_control(struct vpu_graph *graph, struct vpu_frame *frame) |
| { |
| int ret = 0; |
| struct vpu_framemgr *framemgr; |
| |
| BUG_ON(!graph); |
| BUG_ON(!frame); |
| |
| framemgr = &graph->framemgr; |
| |
| if (&graph->control != frame) { |
| vpu_ierr("control frame is invalid(%p == %p)\n", graph, &graph->control, frame); |
| BUG(); |
| } |
| |
| switch (frame->message) { |
| case VPU_CTRL_STOP: |
| graph->control.message = VPU_CTRL_STOP_DONE; |
| wake_up(&graph->control_wq); |
| break; |
| default: |
| vpu_ierr("unresolved message(%d)\n", graph, frame->message); |
| vpu_frame_print_all(framemgr); |
| BUG(); |
| break; |
| } |
| |
| return ret; |
| } |
| |
| static int vpu_graph_request(struct vpu_graph *graph, struct vpu_frame *frame) |
| { |
| int ret = 0; |
| unsigned long flags; |
| struct vpu_framemgr *framemgr; |
| |
| BUG_ON(!graph); |
| BUG_ON(!frame); |
| |
| framemgr = &graph->framemgr; |
| |
| if (frame->state != VPU_FRAME_STATE_REQUEST) { |
| vpu_ierr("frame state(%d) is invalid\n", graph, frame->state); |
| BUG(); |
| } |
| |
| framemgr_e_barrier_irqs(framemgr, 0, flags); |
| vpu_frame_trans_req_to_pre(framemgr, frame); |
| framemgr_x_barrier_irqr(framemgr, 0, flags); |
| |
| if (test_bit(VS4L_CL_FLAG_TIMESTAMP, &frame->flags)) |
| vpu_get_timestamp(&frame->time[VPU_TMP_REQUEST]); |
| |
| return ret; |
| } |
| |
| static int vpu_graph_process(struct vpu_graph *graph, struct vpu_frame *frame) |
| { |
| int ret = 0; |
| unsigned long flags; |
| struct vpu_framemgr *framemgr; |
| |
| BUG_ON(!graph); |
| BUG_ON(!frame); |
| |
| framemgr = &graph->framemgr; |
| |
| if (frame->state != VPU_FRAME_STATE_PREPARE) { |
| vpu_ierr("frame state(%d) is invalid\n", graph, frame->state); |
| BUG(); |
| } |
| |
| framemgr_e_barrier_irqs(framemgr, FMGR_IDX_0, flags); |
| vpu_frame_trans_pre_to_pro(framemgr, frame); |
| framemgr_x_barrier_irqr(framemgr, FMGR_IDX_0, flags); |
| |
| #ifdef DBG_STREAMING |
| vpu_iinfo("PROCESS(%d, %d)\n", graph, frame->index, frame->id); |
| #endif |
| |
| if (test_bit(VS4L_CL_FLAG_TIMESTAMP, &frame->flags)) |
| vpu_get_timestamp(&frame->time[VPU_TMP_PROCESS]); |
| |
| return ret; |
| } |
| |
| static int vpu_graph_cancel(struct vpu_graph *graph, struct vpu_frame *frame) |
| { |
| int ret = 0; |
| unsigned long flags; |
| unsigned long result; |
| struct vpu_framemgr *framemgr; |
| struct vpu_queue *queue; |
| struct vb_container_list *incl, *otcl; |
| |
| BUG_ON(!graph); |
| BUG_ON(!frame); |
| |
| framemgr = &graph->framemgr; |
| queue = &graph->vctx.queue; |
| incl = frame->incl; |
| otcl = frame->otcl; |
| result = 0; |
| |
| if (!test_bit(VPU_GRAPH_STATE_START, &graph->state)) { |
| vpu_ierr("graph is NOT start\n", graph); |
| BUG(); |
| } |
| |
| if (test_bit(VS4L_CL_FLAG_TIMESTAMP, &frame->flags)) { |
| vpu_get_timestamp(&frame->time[VPU_TMP_DONE]); |
| |
| if (incl->flags & (1 << VS4L_CL_FLAG_TIMESTAMP)) |
| memcpy(incl->timestamp, frame->time, sizeof(frame->time)); |
| |
| if (otcl->flags & (1 << VS4L_CL_FLAG_TIMESTAMP)) |
| memcpy(otcl->timestamp, frame->time, sizeof(frame->time)); |
| |
| #ifdef DBG_TIMEMEASURE |
| vpu_irinfo("[TM] G%d : QR(%ld), RP(%ld), PD(%ld)\n", graph, frame, graph->uid, |
| VPU_TIME_IN_US(frame->time[VPU_TMP_REQUEST]) - |
| VPU_TIME_IN_US(frame->time[VPU_TMP_QUEUE]), |
| VPU_TIME_IN_US(frame->time[VPU_TMP_PROCESS]) - |
| VPU_TIME_IN_US(frame->time[VPU_TMP_REQUEST]), |
| VPU_TIME_IN_US(frame->time[VPU_TMP_DONE]) - |
| VPU_TIME_IN_US(frame->time[VPU_TMP_PROCESS])); |
| #endif |
| } |
| |
| vpu_iinfo("CANCEL(%d, %d)\n", graph, frame->index, frame->id); |
| set_bit(VS4L_CL_FLAG_INVALID, &result); |
| |
| switch (frame->state) { |
| case VPU_FRAME_STATE_PREPARE: |
| framemgr_e_barrier_irqs(framemgr, FMGR_IDX_0, flags); |
| vpu_frame_trans_pre_to_com(framemgr, frame); |
| framemgr_x_barrier_irqr(framemgr, FMGR_IDX_0, flags); |
| break; |
| case VPU_FRAME_STATE_PROCESS: |
| framemgr_e_barrier_irqs(framemgr, FMGR_IDX_0, flags); |
| vpu_frame_trans_pro_to_com(framemgr, frame); |
| framemgr_x_barrier_irqr(framemgr, FMGR_IDX_0, flags); |
| break; |
| default: |
| vpu_ierr("frame is invalid(%d)\n", graph, frame->state); |
| vpu_frame_print_all(framemgr); |
| BUG(); |
| break; |
| } |
| |
| graph->cancel_cnt++; |
| vpu_queue_done(queue, incl, otcl, result); |
| |
| return ret; |
| } |
| |
| static int vpu_graph_done(struct vpu_graph *graph, struct vpu_frame *frame) |
| { |
| int ret = 0; |
| unsigned long flags; |
| unsigned long result; |
| struct vpu_framemgr *framemgr; |
| struct vpu_queue *queue; |
| struct vb_container_list *incl, *otcl; |
| |
| BUG_ON(!graph); |
| BUG_ON(!frame); |
| |
| framemgr = &graph->framemgr; |
| queue = &graph->vctx.queue; |
| incl = frame->incl; |
| otcl = frame->otcl; |
| result = 0; |
| |
| if (!test_bit(VPU_GRAPH_STATE_START, &graph->state)) { |
| vpu_ierr("graph is NOT start\n", graph); |
| BUG(); |
| } |
| |
| if (frame->state != VPU_FRAME_STATE_PROCESS) { |
| vpu_ierr("frame state(%d) is invalid\n", graph, frame->state); |
| BUG(); |
| } |
| |
| if (test_bit(VS4L_CL_FLAG_TIMESTAMP, &frame->flags)) { |
| vpu_get_timestamp(&frame->time[VPU_TMP_DONE]); |
| |
| if (incl->flags & (1 << VS4L_CL_FLAG_TIMESTAMP)) |
| memcpy(incl->timestamp, frame->time, sizeof(frame->time)); |
| |
| if (otcl->flags & (1 << VS4L_CL_FLAG_TIMESTAMP)) |
| memcpy(otcl->timestamp, frame->time, sizeof(frame->time)); |
| |
| #ifdef DBG_TIMEMEASURE |
| vpu_irinfo("[TM] G%d : QR(%ld), RR(%ld), RP(%ld), PD(%ld)\n", graph, frame, graph->uid, |
| VPU_TIME_IN_US(frame->time[VPU_TMP_REQUEST]) - |
| VPU_TIME_IN_US(frame->time[VPU_TMP_QUEUE]), |
| VPU_TIME_IN_US(frame->time[VPU_TMP_RESOURCE]) - |
| VPU_TIME_IN_US(frame->time[VPU_TMP_REQUEST]), |
| VPU_TIME_IN_US(frame->time[VPU_TMP_PROCESS]) - |
| VPU_TIME_IN_US(frame->time[VPU_TMP_RESOURCE]), |
| VPU_TIME_IN_US(frame->time[VPU_TMP_DONE]) - |
| VPU_TIME_IN_US(frame->time[VPU_TMP_PROCESS])); |
| #endif |
| } |
| |
| if (frame->param0) { |
| #ifdef DBG_STREAMING |
| vpu_iinfo("NDONE(%d, %d)\n", graph, frame->index, frame->id); |
| #endif |
| set_bit(VS4L_CL_FLAG_DONE, &result); |
| set_bit(VS4L_CL_FLAG_INVALID, &result); |
| } else { |
| #ifdef DBG_STREAMING |
| vpu_iinfo("DONE(%d, %d)\n", graph, frame->index, frame->id); |
| #endif |
| set_bit(VS4L_CL_FLAG_DONE, &result); |
| } |
| |
| if (test_bit(VPU_FRAME_FLAG_IOCPY, &frame->flags)) { |
| /* HACK : direct fetch the result from rois register */ |
| u32 i, target, instance; |
| u32 *result; |
| struct vpuo_pu *pu; |
| |
| for (i = 0; i < frame->otcl->count; ++i) { |
| result = frame->otcl->containers[i].buffers[0].kvaddr; |
| target = frame->otcl->containers[i].target; |
| instance = target & VS4L_TARGET_PU; |
| if ((instance >= VPU_PU_ROIS0) && (instance <= VPU_PU_ROIS1)) { |
| pu = __vpu_graph_find_iopu(&graph->otleaf_list, target); |
| if (!pu) { |
| vpu_err("pu %d is NOT found\n", instance); |
| BUG(); |
| } |
| |
| result[0] = readl(pu->sfr + 0x1C); |
| result[1] = readl(pu->sfr + 0x20); |
| result[2] = readl(pu->sfr + 0x24); |
| result[3] = readl(pu->sfr + 0x28); |
| result[4] = readl(pu->sfr + 0x2C); |
| result[5] = readl(pu->sfr + 0x30); |
| } |
| } |
| } |
| |
| framemgr_e_barrier_irqs(framemgr, FMGR_IDX_0, flags); |
| vpu_frame_trans_pro_to_com(framemgr, frame); |
| framemgr_x_barrier_irqr(framemgr, FMGR_IDX_0, flags); |
| |
| graph->recent = frame->id; |
| graph->done_cnt++; |
| vpu_queue_done(queue, incl, otcl, result); |
| |
| return ret; |
| } |
| |
| static int vpu_graph_get_resource(struct vpu_graph *graph, struct vpu_frame *frame) |
| { |
| int ret = 0; |
| |
| if (!test_bit(VPU_GRAPH_STATE_START, &graph->state)) { |
| vpu_ierr("graph is NOT start\n", graph); |
| BUG(); |
| } |
| |
| if (test_bit(VPU_GRAPH_STATE_HMAPPED, &graph->state)) |
| goto p_err; |
| |
| if (test_bit(VS4L_GRAPH_FLAG_BYPASS, &graph->flags)) |
| goto p_skip; |
| |
| ret = vpu_resource_get(graph->resource, graph->desc_mtask, graph->flags); |
| if (ret > 0) |
| goto p_err; |
| |
| if (ret < 0) { |
| vpu_ierr("vpu_resource_get is fail(%d)\n", graph, ret); |
| goto p_err; |
| } |
| |
| p_skip: |
| if (test_bit(VS4L_CL_FLAG_TIMESTAMP, &frame->flags)) |
| vpu_get_timestamp(&frame->time[VPU_TMP_RESOURCE]); |
| |
| set_bit(VPU_GRAPH_STATE_HMAPPED, &graph->state); |
| |
| p_err: |
| return ret; |
| } |
| |
| static int vpu_graph_put_resource(struct vpu_graph *graph, struct vpu_frame *frame) |
| { |
| int ret = 0; |
| |
| if (!test_bit(VPU_GRAPH_STATE_START, &graph->state)) { |
| vpu_ierr("graph is NOT start\n", graph); |
| BUG(); |
| } |
| |
| if (!test_bit(VPU_GRAPH_STATE_HMAPPED, &graph->state)) |
| goto p_err; |
| |
| if (test_bit(VS4L_GRAPH_FLAG_BYPASS, &graph->flags)) |
| goto p_skip; |
| |
| ret = vpu_resource_put(graph->resource, graph->desc_mtask); |
| if (ret) { |
| vpu_irerr("vpu_resource_put ia fail(%d)\n", graph, frame, ret); |
| goto p_err; |
| } |
| |
| p_skip: |
| clear_bit(VPU_GRAPH_STATE_HMAPPED, &graph->state); |
| |
| p_err: |
| return ret; |
| } |
| |
| static int vpu_graph_update_param(struct vpu_graph *graph, struct vpu_frame *frame) |
| { |
| int ret = 0; |
| struct vpul_task *task; |
| struct vpul_pu_location *pu_loc; |
| union vpul_pu_parameters *update_array; |
| struct vpuo_vertex *vertex; |
| struct vpuo_chain *chain; |
| struct vpuo_pu *pu; |
| u32 i ; |
| |
| task = graph->desc_mtask; |
| pu_loc = fst_updateble_pu_location_ptr(task); |
| |
| if (!graph->update_cnt) |
| goto p_err; |
| |
| update_array = graph->update_array; |
| if (!update_array) { |
| vpu_err("update_vector is NULL\n"); |
| BUG(); |
| } |
| |
| for (i = 0; i < graph->update_cnt; ++i) { |
| if (pu_loc[i].vtx_idx >= graph->vertex_cnt) { |
| vpu_err("vertex index is invalid(%d, %d)\n", |
| pu_loc[i].vtx_idx, graph->vertex_cnt); |
| BUG(); |
| } |
| |
| vertex = graph->vertex_array[pu_loc[i].vtx_idx]; |
| if (!vertex) { |
| vpu_err("vertex is NULL\n"); |
| BUG(); |
| } |
| |
| if (pu_loc[i].sc_idx_in_vtx >= vertex->chain_cnt) { |
| vpu_err("chain index is invalid(%d, %d)\n", |
| pu_loc[i].sc_idx_in_vtx, vertex->chain_cnt); |
| BUG(); |
| } |
| |
| chain = vertex->chain_array[pu_loc[i].sc_idx_in_vtx]; |
| if (!chain) { |
| vpu_err("chain is NULL\n"); |
| BUG(); |
| } |
| |
| if (pu_loc[i].pu_idx_in_sc >= chain->pu_cnt) { |
| vpu_err("pu index is invalid(%d, %d)\n", |
| pu_loc[i].pu_idx_in_sc, chain->pu_cnt); |
| BUG(); |
| } |
| |
| pu = chain->pu_array[pu_loc[i].pu_idx_in_sc]; |
| if (!pu) { |
| vpu_err("pu is NULL\n"); |
| BUG(); |
| } |
| |
| if (!pu->desc_mpu) { |
| vpu_err("desc_mpu is NULL\n"); |
| BUG(); |
| } |
| |
| memcpy(&update_array[i], &pu->desc_mpu->params, sizeof(union vpul_pu_parameters)); |
| } |
| |
| p_err: |
| return ret; |
| } |
| |
| const struct vpu_graph_ops vpu_graph_ops = { |
| .control = vpu_graph_control, |
| .request = vpu_graph_request, |
| .process = vpu_graph_process, |
| .cancel = vpu_graph_cancel, |
| .done = vpu_graph_done, |
| .get_resource = vpu_graph_get_resource, |
| .put_resource = vpu_graph_put_resource, |
| .update_param = vpu_graph_update_param |
| }; |