blob: 51c4f1885f80f8682a75b4b0a2e6144fc653485c [file] [log] [blame]
/*
* 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/types.h>
#include <linux/slab.h>
#include "vpu-config.h"
#include "vpu-exynos.h"
#include "vpu-graph.h"
#include "vpuo-vertex.h"
#include "vpuo-chain.h"
#include "vpuo-pu.h"
int vpuo_pu_create(struct vpuo_pu **pu,
char *desc_ubase,
char *desc_mbase,
struct vpul_pu *desc_upu,
struct vpul_pu *desc_mpu,
void *parent)
{
int ret = 0;
struct vpul_task *desc_task;
struct vpu_graph *graph;
struct vpuo_vertex *vertex;
struct vpuo_chain *chain;
struct vpu_exynos *exynos;
u32 i;
BUG_ON(!pu);
BUG_ON(!desc_ubase);
BUG_ON(!desc_mbase);
BUG_ON(!desc_upu);
BUG_ON(!desc_mpu);
BUG_ON(!parent);
chain = parent;
vertex = chain->parent;
graph = vertex->parent;
exynos = graph->exynos;
desc_task = (struct vpul_task *)desc_mbase;
*pu = kzalloc(sizeof(struct vpuo_pu), GFP_KERNEL);
if (*pu == NULL) {
vpu_err("kzalloc is fail");
ret = -ENOMEM;
goto p_err;
}
(*pu)->id = desc_upu->instance;
(*pu)->index = ((char *)desc_upu - (desc_ubase + desc_task->pus_vec_ofs)) / sizeof(struct vpul_pu);
(*pu)->type = desc_upu->op_type;
(*pu)->level = VPUO_CHAIN_MAX_LEVEL;
(*pu)->target = (chain->id << VS4L_TARGET_SC_SHIFT) | desc_upu->instance;
(*pu)->parent = parent;
(*pu)->buffer_cnt = 0;
(*pu)->inpu_cnt = 0;
(*pu)->otpu_cnt = 0;
(*pu)->desc_upu = desc_upu;
(*pu)->desc_mpu = desc_mpu;
clear_bit(VPUO_PU_STATE_FORMAT, &(*pu)->state);
clear_bit(VPUO_PU_STATE_MAPPED, &(*pu)->state);
clear_bit(VPUO_PU_STATE_IN, &(*pu)->state);
clear_bit(VPUO_PU_STATE_OT, &(*pu)->state);
clear_bit(VPUO_PU_STATE_IM, &(*pu)->state);
(*pu)->sfr = CTL_OP(exynos, ctl_remap, (*pu)->id);
if (!(*pu)->sfr) {
vpu_err("CTL_OP(remap) is fail(%d)\n", ret);
goto p_err;
}
for (i = 0; i < VPUO_PU_MAX_PORT; ++i) {
(*pu)->inpu[i] = NULL;
(*pu)->otpu[i] = NULL;
}
for (i = 0; i < VPUO_PU_MAX_BUFFER; ++i) {
(*pu)->buffer_idx[i] = VPUL_MAX_MAPS_DESC;
(*pu)->buffer_ptr[i] = NULL;
(*pu)->buffer_shm[i] = 0;
(*pu)->buffer[i] = 0;
}
switch ((*pu)->type) {
case VPUL_OP_DMA:
do {
struct vpuo_vertex *vertex;
struct vpul_vertex *desc_vertex;
u32 io_index, map_index, ext_index, mtype;
vertex = chain->parent;
if (!vertex) {
vpu_err("vertex is NULL\n");
BUG();
}
desc_vertex = vertex->desc_mvertex;
if (!desc_vertex) {
vpu_err("desc_vertex is NULL\n");
BUG();
}
io_index = desc_upu->params.dma.inout_index;
if (io_index >= VPUL_MAX_IN_OUT_TYPES) {
vpu_err("io_index is invalid(%d)\n", io_index);
ret = -EINVAL;
goto p_err;
}
if (vertex->type == VPUL_VERTEXT_PROC) {
u32 roi_index;
roi_index = desc_vertex->proc.io.inout_types[io_index].roi_index;
if (desc_vertex->proc.io.inout_types[io_index].is_dynamic) {
if (roi_index >= desc_vertex->proc.io.n_dynamic_map_rois) {
vpu_err("roi_index is invalid(%d > %d)\n", roi_index,
desc_vertex->proc.io.n_dynamic_map_rois);
ret = -EINVAL;
goto p_err;
}
map_index = desc_vertex->proc.io.dynamic_map_roi[roi_index].memmap_idx;
} else {
if (roi_index >= desc_vertex->proc.io.n_fixed_map_roi) {
vpu_err("roi_index is invalid(%d, %d)\n", roi_index,
desc_vertex->proc.io.n_fixed_map_roi);
ret = -EINVAL;
goto p_err;
}
map_index = desc_vertex->proc.io.fixed_map_roi[roi_index].memmap_idx;
}
mtype = desc_task->memmap_desc[map_index].mtype;
if (mtype != VPUL_MEM_EXTERNAL)
break;
ext_index = desc_task->memmap_desc[map_index].index;
if (ext_index >= desc_task->n_external_mem_addresses) {
vpu_err("memory index is invalid(%d)\n", ext_index);
BUG();
}
(*pu)->buffer_cnt = 1;
(*pu)->buffer_idx[0] = ext_index;
(*pu)->buffer_ptr[0] = &desc_task->external_mem_addr[ext_index];
(*pu)->buffer[0] = desc_task->external_mem_addr[ext_index];
} else if (vertex->type == VPUL_VERTEXT_3DNN_PROC) {
struct vpul_3dnn_process_base *process3_base, *process3;
process3_base = (struct vpul_3dnn_process_base *)(desc_mbase + desc_task->process_bases_3dnn_vec_ofs);
process3 = &process3_base[desc_vertex->proc3dnn.base_3dnn_ind];
for (i = 0; i < process3->number_of_layers; ++i) {
map_index = process3->layers[i].inout_3dnn[io_index].mem_descr_index;
mtype = desc_task->memmap_desc[map_index].mtype;
if (mtype != VPUL_MEM_EXTERNAL)
continue;
ext_index = desc_task->memmap_desc[map_index].index;
if (ext_index >= desc_task->n_external_mem_addresses) {
vpu_err("memory index is invalid(%d)\n", ext_index);
BUG();
}
if (ext_index >= VPUL_MAX_TASK_EXTERNAL_RAMS) {
vpu_err("ext_index is over(%d %d)\n", ext_index, VPUL_MAX_TASK_EXTERNAL_RAMS);
BUG();
}
(*pu)->buffer_cnt++;
(*pu)->buffer_idx[i] = ext_index;
(*pu)->buffer_ptr[i] = &desc_task->external_mem_addr[ext_index];
(*pu)->buffer[i] = desc_task->external_mem_addr[ext_index];
}
} else {
vpu_err("vertex type is invalid(%d)\n", vertex->type);
BUG();
}
if ((*pu)->id <= VPU_PU_DMAIN_WIDE1)
set_bit(VPUO_PU_STATE_IN, &(*pu)->state);
else
set_bit(VPUO_PU_STATE_OT, &(*pu)->state);
} while (0);
break;
case VPUL_OP_ROI:
do {
(*pu)->buffer_cnt = 0;
set_bit(VPUO_PU_STATE_OT, &(*pu)->state);
} while (0);
break;
default:
break;
}
p_err:
return ret;
}
int vpuo_pu_destroy(struct vpuo_pu *pu)
{
int ret = 0;
BUG_ON(!pu);
kfree(pu);
return ret;
}