mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
Additional update from Prashant Gaikwad <pgaikwad@nvidia.com> Adapted for Linux 5.13 and the BeagleV Starlight board by <cybergaszcz@gmail.com> kernel test robot: fix platform_no_drv_owner.cocci warnings Geert: Use div_u64() in dla_get_time_us() Signed-off-by: kernel test robot <lkp@intel.com> Link: https://lore.kernel.org/r/20220119060057.GA1143@7f39e361da8f Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> Link: https://lore.kernel.org/r/alpine.DEB.2.22.394.2203090905560.780932@ramsan.of.borg Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
267 lines
6.6 KiB
C
267 lines
6.6 KiB
C
/*
|
|
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <opendla.h>
|
|
#include <dla_debug.h>
|
|
#include <dla_err.h>
|
|
#include <dla_interface.h>
|
|
|
|
#include "dla_engine_internal.h"
|
|
#include "common.h"
|
|
|
|
static const uint32_t map_rdma_ptr_addr[] = {
|
|
0xFFFFFFFF,
|
|
0xFFFFFFFF,
|
|
SDP_REG(RDMA_S_POINTER),
|
|
PDP_REG(RDMA_S_POINTER),
|
|
CDP_REG(RDMA_S_POINTER),
|
|
0xFFFFFFFF,
|
|
};
|
|
|
|
/*
|
|
static const uint32_t map_sts_addr[] = {
|
|
BDMA_REG(STATUS),
|
|
CACC_REG(S_STATUS),
|
|
SDP_REG(S_STATUS),
|
|
PDP_REG(S_STATUS),
|
|
CDP_REG(S_STATUS),
|
|
RBK_REG(S_STATUS),
|
|
};
|
|
*/
|
|
|
|
static const uint32_t map_ptr_addr[] = {
|
|
BDMA_REG(STATUS),
|
|
CACC_REG(S_POINTER),
|
|
SDP_REG(S_POINTER),
|
|
PDP_REG(S_POINTER),
|
|
CDP_REG(S_POINTER),
|
|
RBK_REG(S_POINTER),
|
|
};
|
|
|
|
int32_t dla_enable_intr(uint32_t mask)
|
|
{
|
|
uint32_t reg = glb_reg_read(S_INTR_MASK);
|
|
|
|
reg = reg & (~mask);
|
|
glb_reg_write(S_INTR_MASK, reg);
|
|
|
|
RETURN(0);
|
|
}
|
|
|
|
int32_t dla_disable_intr(uint32_t mask)
|
|
{
|
|
uint32_t reg = glb_reg_read(S_INTR_MASK);
|
|
|
|
reg = reg | mask;
|
|
glb_reg_write(S_INTR_MASK, reg);
|
|
|
|
RETURN(0);
|
|
}
|
|
|
|
/*
|
|
uint8_t bdma_grp_sts[2] = {
|
|
FIELD_ENUM(BDMA_STATUS_0, IDLE, YES),
|
|
FIELD_ENUM(BDMA_STATUS_0, IDLE, YES)
|
|
};
|
|
*/
|
|
|
|
struct dla_roi_desc roi_desc;
|
|
|
|
/*
|
|
* Get DMA data cube address
|
|
*/
|
|
int32_t
|
|
dla_get_dma_cube_address(void *driver_context, void *task_data,
|
|
int16_t index, uint32_t offset, void *dst_ptr,
|
|
uint32_t destination)
|
|
{
|
|
int32_t ret = 0;
|
|
uint64_t *pdst = (uint64_t *)dst_ptr;
|
|
ret = dla_get_dma_address(driver_context, task_data, index,
|
|
dst_ptr, destination);
|
|
if (ret)
|
|
goto exit;
|
|
|
|
pdst[0] += offset;
|
|
|
|
exit:
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Read input buffer address
|
|
*
|
|
* For input layer, in case of static ROI this address is read
|
|
* from address list and index is specified in data cube. In case
|
|
* dynamic ROI, it has to be read depending on ROI information
|
|
* and using surface address
|
|
*
|
|
* For all other layers, this address is read from address list
|
|
* using index specified in data cube
|
|
*/
|
|
int
|
|
dla_read_input_address(struct dla_data_cube *data,
|
|
uint64_t *address,
|
|
int16_t op_index,
|
|
uint8_t roi_index,
|
|
uint8_t bpp)
|
|
{
|
|
uint64_t roi_desc_addr;
|
|
int32_t ret = ERR(INVALID_INPUT);
|
|
struct dla_engine *en = dla_get_engine();
|
|
|
|
/*
|
|
* If memory type is HW then no address required
|
|
*/
|
|
if (data->type == DLA_MEM_HW) {
|
|
ret = 0;
|
|
goto exit;
|
|
}
|
|
|
|
/*
|
|
* If address list index is not -1 means this address has to
|
|
* be read from address list
|
|
*/
|
|
if (data->address != -1) {
|
|
|
|
/*
|
|
* But if other parameters indicate that this is input layer
|
|
* for dynamic ROI then it is an error
|
|
*/
|
|
if (en->network->dynamic_roi &&
|
|
en->network->input_layer == op_index)
|
|
goto exit;
|
|
ret = dla_get_dma_cube_address(en->driver_context,
|
|
en->task->task_data,
|
|
data->address,
|
|
data->offset,
|
|
(void *)address,
|
|
DESTINATION_DMA);
|
|
goto exit;
|
|
}
|
|
|
|
/*
|
|
* Check if it is dynamic ROI and this is input layer
|
|
*/
|
|
if (en->network->dynamic_roi && en->network->input_layer == op_index) {
|
|
if (!en->task->surface_addr)
|
|
goto exit;
|
|
|
|
/* Calculate address of ROI descriptor in array */
|
|
roi_desc_addr = en->task->roi_array_addr;
|
|
|
|
/* Read ROI descriptor */
|
|
ret = dla_data_read(en->driver_context,
|
|
en->task->task_data,
|
|
roi_desc_addr,
|
|
(void *)&roi_desc,
|
|
sizeof(roi_desc),
|
|
sizeof(struct dla_roi_array_desc) +
|
|
roi_index * sizeof(struct dla_roi_desc));
|
|
if (ret)
|
|
goto exit;
|
|
|
|
/* Calculate ROI address */
|
|
*address = en->task->surface_addr;
|
|
*address += (roi_desc.top * data->line_stride) +
|
|
(bpp * roi_desc.left);
|
|
}
|
|
|
|
exit:
|
|
RETURN(ret);
|
|
}
|
|
|
|
int
|
|
utils_get_free_group(struct dla_processor *processor,
|
|
uint8_t *group_id,
|
|
uint8_t *rdma_id)
|
|
{
|
|
int32_t ret = 0;
|
|
uint32_t pointer;
|
|
uint32_t hw_consumer_ptr;
|
|
uint32_t hw_rdma_ptr;
|
|
|
|
hw_rdma_ptr = 0;
|
|
|
|
if (processor->op_type == DLA_OP_BDMA) {
|
|
pointer = reg_read(map_ptr_addr[processor->op_type]);
|
|
hw_consumer_ptr = ((pointer & MASK(BDMA_STATUS_0, GRP0_BUSY)) >>
|
|
SHIFT(BDMA_STATUS_0, GRP0_BUSY)) ==
|
|
FIELD_ENUM(BDMA_STATUS_0, GRP0_BUSY, YES) ?
|
|
1 : 0;
|
|
} else {
|
|
pointer = reg_read(map_ptr_addr[processor->op_type]);
|
|
hw_consumer_ptr = (pointer & MASK(CDP_S_POINTER_0, CONSUMER)) >>
|
|
SHIFT(CDP_S_POINTER_0, CONSUMER);
|
|
|
|
/*
|
|
* Read current consumer pointer for RDMA only if processor
|
|
* has RDMA module
|
|
*/
|
|
if (map_rdma_ptr_addr[processor->op_type] != 0xFFFFFFFF) {
|
|
pointer =
|
|
reg_read(map_rdma_ptr_addr[processor->op_type]);
|
|
hw_rdma_ptr = (pointer &
|
|
MASK(CDP_S_POINTER_0, CONSUMER)) >>
|
|
SHIFT(CDP_S_POINTER_0, CONSUMER);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If both processors are programmed then exit
|
|
*/
|
|
if (processor->group_status == 0x3) {
|
|
ret = ERR(PROCESSOR_BUSY);
|
|
goto exit;
|
|
}
|
|
|
|
if (!processor->group_status)
|
|
/*
|
|
* If both groups are idle then use consumer pointer
|
|
*/
|
|
*group_id = hw_consumer_ptr;
|
|
else
|
|
/*
|
|
* Here it is assumed that only one group is idle or busy
|
|
* and hence right shift will work to get correct
|
|
* group id
|
|
*/
|
|
*group_id = !(processor->group_status >> 1);
|
|
|
|
/*
|
|
* If both groups are idle then read group id from pointer
|
|
*/
|
|
if (!processor->rdma_status)
|
|
*rdma_id = hw_rdma_ptr;
|
|
else
|
|
*rdma_id = !(processor->rdma_status >> 1);
|
|
|
|
exit:
|
|
RETURN(ret);
|
|
}
|