diff --git a/mpp/hal/worker/mpp_device/mpp_device.c b/mpp/hal/worker/mpp_device/mpp_device.c index 001ce108..1a40a63f 100644 --- a/mpp/hal/worker/mpp_device/mpp_device.c +++ b/mpp/hal/worker/mpp_device/mpp_device.c @@ -104,52 +104,6 @@ static MPP_RET mpp_check_cmd_valid(RK_U32 cmd, MppDevCtxImpl *p) return ret; } -static RK_U32 mpp_probe_hw_support(RK_S32 dev) -{ - RK_S32 ret; - RK_U32 flag = 0; - MppReqV1 mpp_req; - - mpp_req.cmd = MPP_CMD_PROBE_HW_SUPPORT; - mpp_req.flag = 0; - mpp_req.size = 0; - mpp_req.offset = 0; - mpp_req.data_ptr = REQ_DATA_PTR(&flag); - - ret = (RK_S32)ioctl(dev, MPP_IOC_CFG_V1, &mpp_req); - if (ret) { - mpp_err_f("probe hw support error %s.\n", strerror(errno)); - flag = 0; - } else { - mpp_refresh_vcodec_type(flag); - mpp_dev_dbg_hw_cap("vcodec_support %08x\n", flag); - } - - return flag; -} - -static RK_U32 mpp_get_hw_id(RK_S32 dev) -{ - RK_S32 ret; - RK_U32 flag = 0; - MppReqV1 mpp_req; - - mpp_req.cmd = MPP_CMD_QUERY_HW_ID; - mpp_req.flag = 0; - mpp_req.size = 0; - mpp_req.offset = 0; - mpp_req.data_ptr = REQ_DATA_PTR(&flag); - - ret = (RK_S32)ioctl(dev, MPP_IOC_CFG_V1, &mpp_req); - if (ret) { - mpp_err_f("get hw id error %s.\n", strerror(errno)); - flag = 0; - } - - mpp_dev_dbg_hw_cap("hardware version 0x%8x", flag); - return flag; -} - static RK_S32 mpp_device_set_client_type(MppDevCtx ctx, int dev, RK_S32 client_type) { RK_S32 ret; @@ -266,10 +220,8 @@ MPP_RET mpp_device_init(MppDevCtx *ctx, MppDevCfg *cfg) RK_S32 ret; /* if ioctl_version is 1, query hw supprot*/ - if (p->ioctl_version > 0) { + if (p->ioctl_version > 0) p->cap = mpp_get_mpp_service_cmd_cap(); - mpp_probe_hw_support(dev); - } client_type = mpp_device_get_client_type(p, p->type, p->coding); ret = mpp_device_set_client_type(p, dev, client_type); @@ -287,7 +239,7 @@ MPP_RET mpp_device_init(MppDevCtx *ctx, MppDevCfg *cfg) *ctx = p; p->vpu_fd = dev; if (p->ioctl_version > 0) - cfg->hw_id = mpp_get_hw_id(dev); + cfg->hw_id = mpp_get_client_hw_id(p->client_type); else cfg->hw_id = 0; diff --git a/osal/CMakeLists.txt b/osal/CMakeLists.txt index ed3b674c..d2126b1d 100644 --- a/osal/CMakeLists.txt +++ b/osal/CMakeLists.txt @@ -25,6 +25,12 @@ set(MPP_ALLOCATOR ${DRM_FILES} ) +set(MPP_DRIVER + driver/mpp_device_v2.c + driver/mpp_service.c + driver/vcodec_service.c +) + add_library(osal STATIC mpp_platform.cpp mpp_runtime.cpp @@ -53,6 +59,7 @@ add_library(osal STATIC windows/os_env.c windows/os_log.c ${MPP_ALLOCATOR} + ${MPP_DRIVER} ) target_link_libraries(osal ${CMAKE_THREAD_LIBS_INIT}) diff --git a/osal/driver/mpp_device_v2.c b/osal/driver/mpp_device_v2.c new file mode 100644 index 00000000..dd3501b8 --- /dev/null +++ b/osal/driver/mpp_device_v2.c @@ -0,0 +1,150 @@ +/* + * Copyright 2020 Rockchip Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define MODULE_TAG "mpp_device" + +#include + +#include "mpp_log.h" +#include "mpp_mem.h" +#include "mpp_platform.h" + +#include "mpp_device_api.h" +#include "mpp_service_api.h" +#include "vcodec_service_api.h" + +typedef struct MppDevImpl_t { + MppClientType type; + + void *ctx; + const MppDevApi *api; +} MppDevImpl; + +MPP_RET mpp_dev_init(MppDev *ctx, MppClientType type) +{ + if (NULL == ctx) { + mpp_err_f("found NULL input ctx\n"); + return MPP_ERR_NULL_PTR; + } + + *ctx = NULL; + + RK_U32 codec_type = mpp_get_vcodec_type(); + if (!(codec_type & (1 << type))) { + mpp_err_f("found unsupported client type %d in platform %x\n", + type, codec_type); + return MPP_ERR_VALUE; + } + + MppIoctlVersion ioctl_version = mpp_get_ioctl_version(); + const MppDevApi *api = NULL; + + switch (ioctl_version) { + case IOCTL_VCODEC_SERVICE : { + api = &vcodec_service_api; + } break; + case IOCTL_MPP_SERVICE_V1 : { + api = &mpp_service_api; + } break; + default : { + mpp_err_f("invalid ioctl verstion %d\n", ioctl_version); + return MPP_NOK; + } break; + } + + MppDevImpl *impl = mpp_calloc(MppDevImpl, 1); + void *impl_ctx = mpp_calloc_size(void, api->ctx_size); + if (NULL == impl || NULL == impl_ctx) { + mpp_err_f("malloc failed impl %p impl_ctx %p\n", impl, impl_ctx); + MPP_FREE(impl); + MPP_FREE(impl_ctx); + return MPP_ERR_MALLOC; + } + + impl->ctx = impl_ctx; + impl->api = api; + impl->type = type; + *ctx = impl; + + return api->init(impl_ctx, type); +} + +MPP_RET mpp_dev_deinit(MppDev ctx) +{ + if (NULL == ctx) { + mpp_err_f("found NULL input ctx\n"); + return MPP_ERR_NULL_PTR; + } + + MppDevImpl *p = (MppDevImpl *)ctx; + MPP_RET ret = MPP_OK; + + if (p->api && p->api->deinit && p->ctx) + ret = p->api->deinit(p->ctx); + + MPP_FREE(p->ctx); + MPP_FREE(p); + + return ret; +} + +MPP_RET mpp_dev_ioctl(MppDev ctx, RK_S32 cmd, void *param) +{ + if (NULL == ctx) { + mpp_err_f("found NULL input ctx\n"); + return MPP_ERR_NULL_PTR; + } + + MppDevImpl *p = (MppDevImpl *)ctx; + const MppDevApi *api = p->api; + void *impl_ctx = p->ctx; + MPP_RET ret = MPP_OK; + + if (NULL == ctx || NULL == api) + return ret; + + switch (cmd) { + case MPP_DEV_REG_WR : { + if (api->reg_wr) + ret = api->reg_wr(impl_ctx, param); + } break; + case MPP_DEV_REG_RD : { + if (api->reg_rd) + ret = api->reg_rd(impl_ctx, param); + } break; + case MPP_DEV_FD_TRANS : { + if (api->fd_trans) + ret = api->fd_trans(impl_ctx, param); + } break; + case MPP_DEV_SET_INFO : { + if (api->set_info) + ret = api->set_info(impl_ctx, param); + } break; + case MPP_DEV_CMD_SEND : { + if (api->cmd_send) + ret = api->cmd_send(impl_ctx); + } break; + case MPP_DEV_CMD_POLL : { + if (api->cmd_poll) + ret = api->cmd_poll(impl_ctx); + } break; + default : { + mpp_err_f("invalid cmd %d\n", cmd); + } break; + } + + return ret; +} diff --git a/osal/driver/mpp_service.c b/osal/driver/mpp_service.c new file mode 100644 index 00000000..d21fc144 --- /dev/null +++ b/osal/driver/mpp_service.c @@ -0,0 +1,412 @@ +/* + * Copyright 2020 Rockchip Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define MODULE_TAG "mpp_serivce" + +#include +#include +#include +#include + +#include "mpp_env.h" +#include "mpp_log.h" +#include "mpp_common.h" + +#include "mpp_service.h" +#include "mpp_service_api.h" + +#define MPP_SERVICE_DBG_FUNC (0x00000001) +#define MPP_SERVICE_DBG_PROBE (0x00000002) + +#define mpp_srv_dbg(flag, fmt, ...) _mpp_dbg(mpp_service_debug, flag, fmt, ## __VA_ARGS__) +#define mpp_srv_dbg_f(flag, fmt, ...) _mpp_dbg_f(mpp_service_debug, flag, fmt, ## __VA_ARGS__) + +#define mpp_src_dbg_func(fmt, ...) mpp_srv_dbg_f(MPP_SERVICE_DBG_FUNC, fmt, ## __VA_ARGS__) +#define mpp_src_dbg_probe(fmt, ...) mpp_srv_dbg(MPP_SERVICE_DBG_PROBE, fmt, ## __VA_ARGS__) + +static RK_U32 mpp_service_debug = 0; + +typedef struct MppServiceQueryCfg_t { + RK_U32 cmd_butt; + const char *name; +} MppServiceQueryCfg; + +static const MppServiceQueryCfg query_cfg[] = { + { MPP_CMD_QUERY_BASE, "query_cmd", }, + { MPP_CMD_INIT_BASE, "init_cmd", }, + { MPP_CMD_SEND_BASE, "query_cmd", }, + { MPP_CMD_POLL_BASE, "init_cmd", }, + { MPP_CMD_CONTROL_BASE, "control_cmd", }, +}; + +static const RK_U32 query_count = MPP_ARRAY_ELEMS(query_cfg); + +static const char *mpp_service_hw_name[] = { + /* 0 ~ 3 */ + /* VPU_CLIENT_VDPU1 */ "vdpu1", + /* VPU_CLIENT_VDPU2 */ "vdpu2", + /* VPU_CLIENT_VDPU1_PP */ "vdpu1_pp", + /* VPU_CLIENT_VDPU2_PP */ "vdpu2_pp", + /* 4 ~ 7 */ + /* VPU_CLIENT_BUTT */ NULL, + /* VPU_CLIENT_BUTT */ NULL, + /* VPU_CLIENT_BUTT */ NULL, + /* VPU_CLIENT_BUTT */ NULL, + /* 8 ~ 11 */ + /* VPU_CLIENT_HEVC_DEC */ "rkhevc", + /* VPU_CLIENT_RKVDEC */ "rkvdec", + /* VPU_CLIENT_BUTT */ NULL, + /* VPU_CLIENT_BUTT */ NULL, + /* 12 ~ 15 */ + /* VPU_CLIENT_AVSPLUS_DEC */ "avsd", + /* VPU_CLIENT_BUTT */ NULL, + /* VPU_CLIENT_BUTT */ NULL, + /* VPU_CLIENT_BUTT */ NULL, + /* 16 ~ 19 */ + /* VPU_CLIENT_RKVENC */ "rkvenc", + /* VPU_CLIENT_VEPU1 */ "vepu1", + /* VPU_CLIENT_VEPU2 */ "vepu2", + /* VPU_CLIENT_VEPU2_LITE */ "vepu2_lite", + /* 20 ~ 23 */ + /* VPU_CLIENT_BUTT */ NULL, + /* VPU_CLIENT_BUTT */ NULL, + /* VPU_CLIENT_BUTT */ NULL, + /* VPU_CLIENT_BUTT */ NULL, + /* 24 ~ 27 */ + /* VPU_CLIENT_VEPU22 */ "vepu22", + /* VPU_CLIENT_BUTT */ NULL, + /* VPU_CLIENT_BUTT */ NULL, + /* VPU_CLIENT_BUTT */ NULL, + /* 28 ~ 31 */ + /* IEP_CLIENT_TYPE */ "iep", + /* VPU_CLIENT_BUTT */ NULL, + /* VPU_CLIENT_BUTT */ NULL, + /* VPU_CLIENT_BUTT */ NULL, +}; + +static const char *mpp_service_name = "/dev/mpp_service"; + +static RK_S32 mpp_service_ioctl(RK_S32 fd, RK_U32 cmd, RK_U32 size, void *param) +{ + MppReqV1 mpp_req; + + memset(&mpp_req, 0, sizeof(mpp_req)); + + mpp_req.cmd = cmd; + mpp_req.flag = 0; + mpp_req.size = size; + mpp_req.offset = 0; + mpp_req.data_ptr = REQ_DATA_PTR(param); + + return (RK_S32)ioctl(fd, MPP_IOC_CFG_V1, &mpp_req); +} + +static RK_S32 mpp_service_ioctl_request(RK_S32 fd, MppReqV1 *req) +{ + return (RK_S32)ioctl(fd, MPP_IOC_CFG_V1, req); +} + +void check_mpp_service_cap(RK_U32 *codec_type, RK_U32 *hw_ids, MppServiceCmdCap *cap) +{ + MppReqV1 mpp_req; + RK_S32 fd = -1; + RK_S32 ret = 0; + RK_U32 *cmd_butt = &cap->query_cmd;; + RK_U32 val; + RK_U32 i; + + mpp_env_get_u32("mpp_service_debug", &mpp_service_debug, 0); + + *codec_type = 0; + memset(hw_ids, 0, sizeof(RK_U32) * 32); + + fd = open(mpp_service_name, O_RDWR); + if (fd < 0) { + mpp_err("open mpp_service to check cmd capability failed\n"); + memset(cap, 0, sizeof(*cap)); + return ; + } + + /* check hw_support flag for valid client type */ + ret = mpp_service_ioctl(fd, MPP_CMD_PROBE_HW_SUPPORT, 0, &val); + if (!ret) { + mpp_src_dbg_probe("vcodec_support %08x\n", val); + *codec_type = val; + } + + /* check each valid client type for hw_id */ + { + RK_U32 hw_support = val; + + /* find first valid client type */ + for (i = 0; i < 32; i++) + if (hw_support & (1 << i)) { + val = i; + break; + } + + /* for compatible check hw_id read mode first */ + ret = mpp_service_ioctl(fd, MPP_CMD_QUERY_HW_ID, sizeof(val), &val); + if (!ret) { + /* kernel support hw_id check by input client type */ + for (i = 0; i < 32; i++) { + if (hw_support & (1 << i)) { + val = i; + + /* send client type and get hw_id */ + ret = mpp_service_ioctl(fd, MPP_CMD_QUERY_HW_ID, sizeof(val), &val); + if (!ret) { + mpp_src_dbg_probe("client %-10s hw_id %08x\n", mpp_service_hw_name[i], val); + hw_ids[i] = val; + } else + mpp_err("check valid client %-10s for hw_id failed\n", + mpp_service_hw_name[i]); + } + } + } else { + /* kernel need to set client type then get hw_id */ + for (i = 0; i < 32; i++) { + if (hw_support & (1 << i)) { + val = i; + + /* set client type first */ + ret = mpp_service_ioctl(fd, MPP_CMD_INIT_CLIENT_TYPE, sizeof(val), &val); + if (ret) { + mpp_err("check valid client type %d failed\n", i); + continue; + } + + /* then get hw_id */ + ret = mpp_service_ioctl(fd, MPP_CMD_QUERY_HW_ID, sizeof(val), &val); + if (!ret) { + mpp_src_dbg_probe("client %-10s hw_id %08x\n", mpp_service_hw_name[i], val); + hw_ids[i] = val; + } else + mpp_err("check valid client %-10s for hw_id failed\n", + mpp_service_hw_name[i]); + } + } + } + } + + cap->support_cmd = access("/proc/mpp_service/support_cmd", F_OK) ? 0 : 1; + if (!cap->support_cmd) + return ; + + for (i = 0; i < query_count; i++, cmd_butt++) { + const MppServiceQueryCfg *cfg = &query_cfg[i]; + + memset(&mpp_req, 0, sizeof(mpp_req)); + + val = cfg->cmd_butt; + mpp_req.cmd = MPP_CMD_QUERY_CMD_SUPPORT; + mpp_req.data_ptr = REQ_DATA_PTR(&val); + + ret = (RK_S32)ioctl(fd, MPP_IOC_CFG_V1, &mpp_req); + if (ret) + mpp_err_f("query %-11s support error %s.\n", cfg->name, strerror(errno)); + else { + *cmd_butt = val; + mpp_src_dbg_probe("query %-11s support %04x\n", cfg->name, val); + } + } + + close(fd); +} + +#define MAX_FD_TRANS 16 + +typedef struct FdTransInfo_t { + RK_U32 reg_idx; + RK_U32 offset; +} FdTransInfo; + +typedef struct MppDevMppService_t { + RK_S32 client_type; + RK_S32 fd; + + RK_S32 req_cnt; + MppReqV1 reqs[MAX_REQ_NUM]; + RK_S32 fd_trans_count; + FdTransInfo fd_trans_info[MAX_FD_TRANS]; + + /* support max cmd buttom */ + const MppServiceCmdCap *cap; +} MppDevMppService; + +MPP_RET mpp_service_init(void *ctx, MppClientType type) +{ + MppDevMppService *p = (MppDevMppService *)ctx; + MPP_RET ret = MPP_NOK; + + p->cap = mpp_get_mpp_service_cmd_cap(); + p->fd = open(mpp_service_name, O_RDWR); + if (p->fd < 0) { + mpp_err("open mpp_service failed\n"); + return ret; + } + + /* set client type first */ + ret = mpp_service_ioctl(p->fd, MPP_CMD_INIT_CLIENT_TYPE, sizeof(type), &type); + if (ret) + mpp_err("set client type %d failed\n", type); + + return ret; +} + +MPP_RET mpp_service_deinit(void *ctx) +{ + MppDevMppService *p = (MppDevMppService *)ctx; + if (p->fd) + close(p->fd); + + return MPP_OK; +} + +MPP_RET mpp_service_reg_wr(void *ctx, MppDevRegWrCfg *cfg) +{ + MppDevMppService *p = (MppDevMppService *)ctx; + + if (!p->req_cnt) + memset(p->reqs, 0, sizeof(p->reqs)); + + MppReqV1 *mpp_req = &p->reqs[p->req_cnt]; + + mpp_req->cmd = MPP_CMD_SET_REG_WRITE; + mpp_req->flag = 0; + mpp_req->size = cfg->size; + mpp_req->offset = cfg->offset; + mpp_req->data_ptr = REQ_DATA_PTR(cfg->reg); + p->req_cnt++; + + return MPP_OK; +} + +MPP_RET mpp_service_reg_rd(void *ctx, MppDevRegRdCfg *cfg) +{ + MppDevMppService *p = (MppDevMppService *)ctx; + + if (!p->req_cnt) + memset(p->reqs, 0, sizeof(p->reqs)); + + MppReqV1 *mpp_req = &p->reqs[p->req_cnt]; + + mpp_req->cmd = MPP_CMD_SET_REG_READ; + mpp_req->flag = 0; + mpp_req->size = cfg->size; + mpp_req->offset = cfg->offset; + mpp_req->data_ptr = REQ_DATA_PTR(cfg->reg); + p->req_cnt++; + + return MPP_OK; +} + +MPP_RET mpp_service_fd_trans(void *ctx, MppDevFdTransCfg *cfg) +{ + MppDevMppService *p = (MppDevMppService *)ctx; + + if (!cfg->offset) + return MPP_OK; + + FdTransInfo *info = &p->fd_trans_info[p->fd_trans_count++]; + + info->reg_idx = cfg->reg_idx; + info->offset = cfg->offset; + + return MPP_OK; +} + +MPP_RET mpp_service_set_info(void *ctx, MppDevSetInfoCfg *cfg) +{ + (void)ctx; + (void)cfg; + + return MPP_OK; +} + +MPP_RET mpp_service_cmd_send(void *ctx) +{ + MppDevMppService *p = (MppDevMppService *)ctx; + + if (p->req_cnt <= 0 || p->req_cnt > MAX_REQ_NUM) { + mpp_err_f("ctx %p invalid request count %d\n", ctx, p->req_cnt); + return MPP_ERR_VALUE; + } + + /* set fd trans info if needed */ + if (p->fd_trans_count) { + MppReqV1 *mpp_req = &p->reqs[p->req_cnt]; + + mpp_req->cmd = MPP_CMD_SET_REG_ADDR_OFFSET; + mpp_req->flag = 0; + mpp_req->size = p->fd_trans_count * sizeof(p->fd_trans_info[0]); + mpp_req->offset = 0; + mpp_req->data_ptr = REQ_DATA_PTR(&p->fd_trans_info[0]); + p->req_cnt++; + } + + /* setup flag for multi message request */ + if (p->req_cnt > 1) { + RK_S32 i; + + for (i = 0; i < p->req_cnt; i++) + p->reqs[i].flag |= MPP_FLAGS_MULTI_MSG; + } + p->reqs[p->req_cnt - 1].flag |= MPP_FLAGS_LAST_MSG; + + MPP_RET ret = mpp_service_ioctl_request(p->fd, &p->reqs[0]); + if (ret) { + mpp_err_f("ioctl MPP_IOC_CFG_V1 failed ret %d errno %d %s\n", + ret, errno, strerror(errno)); + ret = errno; + } + + p->req_cnt = 0; + p->fd_trans_count = 0; + return ret; +} + +MPP_RET mpp_service_cmd_poll(void *ctx) +{ + MppDevMppService *p = (MppDevMppService *)ctx; + MppReqV1 dev_req; + + memset(&dev_req, 0, sizeof(dev_req)); + dev_req.cmd = MPP_CMD_POLL_HW_FINISH; + dev_req.flag |= MPP_FLAGS_LAST_MSG; + + MPP_RET ret = mpp_service_ioctl_request(p->fd, &dev_req); + if (ret) { + mpp_err_f("ioctl MPP_IOC_CFG_V1 failed ret %d errno %d %s\n", + ret, errno, strerror(errno)); + ret = errno; + } + + return ret; +} + +const MppDevApi mpp_service_api = { + "mpp_service", + sizeof(MppDevMppService), + mpp_service_init, + mpp_service_deinit, + mpp_service_reg_wr, + mpp_service_reg_rd, + mpp_service_fd_trans, + mpp_service_set_info, + mpp_service_cmd_send, + mpp_service_cmd_poll, +}; diff --git a/osal/driver/vcodec_service.c b/osal/driver/vcodec_service.c new file mode 100644 index 00000000..2c505558 --- /dev/null +++ b/osal/driver/vcodec_service.c @@ -0,0 +1,369 @@ +/* + * Copyright 2020 Rockchip Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define MODULE_TAG "vcodec_service" + +#include +#include +#include +#include +#include + +#include "mpp_env.h" +#include "mpp_log.h" +#include "mpp_mem.h" +#include "mpp_time.h" +#include "mpp_list.h" +#include "mpp_common.h" + +#include "vpu.h" +#include "vcodec_service.h" +#include "vcodec_service_api.h" + +#define MAX_REGS_COUNT 3 +#define MPX_EXTRA_INFO_NUM 16 + +typedef struct VcodecExtraSlot_t { + RK_U32 reg_idx; + RK_U32 offset; +} VcodecExtraSlot; + +typedef struct VcodecExtraInfo_t { + RK_U32 magic; // Fix magic value 0x4C4A46 + RK_U32 count; // valid patch info count + VcodecExtraSlot slots[MPX_EXTRA_INFO_NUM]; +} VcodecExtraInfo; + +typedef struct VcodecRegCfg_t { + RK_U32 reg_size; + VcodecExtraInfo extra_info; + + void *reg_set; + void *reg_get; +} VcodecRegCfg; + +typedef struct MppDevVcodecService_t { + RK_S32 client_type; + RK_S32 fd; + RK_S32 max_regs; + RK_U32 reg_size; + + RK_S32 reg_send_idx; + RK_S32 reg_poll_idx; + + VcodecRegCfg regs[MAX_REGS_COUNT]; +} MppDevVcodecService; + +/* For vpu1 / vpu2 */ +static const char *mpp_vpu_dev[] = { + "/dev/vpu_service", + "/dev/vpu-service", +}; + +/* For hevc 4K decoder */ +static const char *mpp_hevc_dev[] = { + "/dev/hevc_service", + "/dev/hevc-service", +}; + +/* For H.264/H.265/VP9 4K decoder */ +static const char *mpp_rkvdec_dev[] = { + "/dev/rkvdec", +}; + +/* For H.264 4K encoder */ +static const char *mpp_rkvenc_dev[] = { + "/dev/rkvenc", +}; + +/* For avs+ decoder */ +static const char *mpp_avsd_dev[] = { + "/dev/avsd", +}; + +/* For H.264 / jpeg encoder */ +static const char *mpp_vepu_dev[] = { + "/dev/vepu", +}; + +#define mpp_find_device(dev) _mpp_find_device(dev, MPP_ARRAY_ELEMS(dev)) + +static const char *_mpp_find_device(const char **dev, RK_U32 size) +{ + RK_U32 i; + + for (i = 0; i < size; i++) + if (!access(dev[i], F_OK)) + return dev[i]; + + return NULL; +} + +static RK_S32 vcodec_service_ioctl(RK_S32 fd, RK_S32 cmd, void *regs, RK_S32 size) +{ + MppReq req; + + req.req = regs; + req.size = size; + + return (RK_S32)ioctl(fd, cmd, &req); +} + +static void extra_info_init(VcodecExtraInfo *info) +{ + info->magic = EXTRA_INFO_MAGIC; + info->count = 0; +} + +MPP_RET vcodec_service_init(void *ctx, MppClientType type) +{ + MppDevVcodecService *p = (MppDevVcodecService *)ctx; + static RK_S32 vcodec_ioctl_version = -1; + VPU_CLIENT_TYPE client_type; + const char *name = NULL; + RK_U32 reg_size = 0; + RK_S32 max_regs = 2; + MPP_RET ret = MPP_NOK; + + switch (type) { + case VPU_CLIENT_VDPU1 : { + name = mpp_find_device(mpp_vpu_dev); + client_type = VPU_DEC; + reg_size = VDPU1_REGISTERS; + } break; + case VPU_CLIENT_VDPU2 : { + name = mpp_find_device(mpp_vpu_dev); + client_type = VPU_DEC; + reg_size = VDPU2_REGISTERS; + } break; + case VPU_CLIENT_VDPU1_PP : { + name = mpp_find_device(mpp_vpu_dev); + client_type = VPU_DEC_PP; + reg_size = VDPU1_PP_REGISTERS; + } break; + case VPU_CLIENT_VDPU2_PP : { + name = mpp_find_device(mpp_vpu_dev); + client_type = VPU_DEC_PP; + reg_size = VDPU2_PP_REGISTERS; + } break; + case VPU_CLIENT_HEVC_DEC : { + name = mpp_find_device(mpp_hevc_dev); + client_type = VPU_DEC; + reg_size = RKHEVC_REGISTERS; + max_regs = 3; + } break; + case VPU_CLIENT_RKVDEC : { + name = mpp_find_device(mpp_rkvdec_dev); + client_type = VPU_DEC; + reg_size = RKVDEC_REGISTERS; + max_regs = 3; + } break; + case VPU_CLIENT_AVSPLUS_DEC : { + name = mpp_find_device(mpp_avsd_dev); + client_type = VPU_DEC; + reg_size = AVSD_REGISTERS; + } break; + case VPU_CLIENT_RKVENC : { + name = mpp_find_device(mpp_rkvenc_dev); + client_type = VPU_ENC; + reg_size = AVSD_REGISTERS; + } break; + case VPU_CLIENT_VEPU1 : { + name = mpp_find_device(mpp_vpu_dev); + client_type = VPU_ENC; + reg_size = VEPU1_REGISTERS; + } break; + case VPU_CLIENT_VEPU2 : { + name = mpp_find_device(mpp_vpu_dev); + client_type = VPU_ENC; + reg_size = VEPU2_REGISTERS; + } break; + case VPU_CLIENT_VEPU2_LITE : { + name = mpp_find_device(mpp_vepu_dev); + if (name == NULL) + name = mpp_find_device(mpp_vpu_dev); + client_type = VPU_ENC; + reg_size = VEPU2_REGISTERS; + } break; + default : { + mpp_err_f("unsupported client type %d\n", type); + return ret; + } break; + } + + p->fd = open(name, O_RDWR); + if (p->fd < 0) { + mpp_err("open vcodec_service %s failed\n", name); + return ret; + } + + if (vcodec_ioctl_version < 0) { + ret = (RK_S32)ioctl(p->fd, VPU_IOC_SET_CLIENT_TYPE, (unsigned long)client_type); + if (!ret) { + vcodec_ioctl_version = 0; + } else { + ret = (RK_S32)ioctl(p->fd, VPU_IOC_SET_CLIENT_TYPE_U32, (RK_U32)client_type); + if (!ret) + vcodec_ioctl_version = 1; + } + mpp_assert(ret == MPP_OK); + } else { + RK_U32 cmd = (vcodec_ioctl_version == 0) ? + (VPU_IOC_SET_CLIENT_TYPE) : + (VPU_IOC_SET_CLIENT_TYPE_U32); + + ret = (RK_S32)ioctl(p->fd, cmd, client_type); + } + + p->max_regs = max_regs; + p->reg_size = reg_size * sizeof(RK_U32); + { + RK_S32 i; + + for (i = 0; i < max_regs; i++) { + VcodecRegCfg *reg = &p->regs[i]; + + reg->reg_size = p->reg_size; + extra_info_init(®->extra_info); + } + } + + + return ret; +} + +MPP_RET vcodec_service_deinit(void *ctx) +{ + MppDevVcodecService *p = (MppDevVcodecService *)ctx; + + if (p->fd) + close(p->fd); + + return MPP_OK; +} + +MPP_RET vcodec_service_reg_wr(void *ctx, MppDevRegWrCfg *cfg) +{ + MppDevVcodecService *p = (MppDevVcodecService *)ctx; + VcodecRegCfg *send_cfg = &p->regs[p->reg_send_idx]; + + mpp_assert(cfg->offset == 0); + send_cfg->reg_set = cfg->reg; + send_cfg->reg_size = cfg->size; + + if (p->reg_size != cfg->size) + mpp_err_f("reg size mismatch wr %d rd %d\n", + p->reg_size, cfg->size); + + return MPP_OK; +} + +MPP_RET vcodec_service_reg_rd(void *ctx, MppDevRegRdCfg *cfg) +{ + MppDevVcodecService *p = (MppDevVcodecService *)ctx; + VcodecRegCfg *send_cfg = &p->regs[p->reg_send_idx]; + + mpp_assert(cfg->offset == 0); + send_cfg->reg_get = cfg->reg; + if (send_cfg->reg_size != cfg->size) + mpp_err_f("reg size mismatch rd %d rd %d\n", + send_cfg->reg_size, cfg->size); + + return MPP_OK; +} + +MPP_RET vcodec_service_fd_trans(void *ctx, MppDevFdTransCfg *cfg) +{ + if (cfg->offset) { + MppDevVcodecService *p = (MppDevVcodecService *)ctx; + VcodecRegCfg *send_cfg = &p->regs[p->reg_send_idx]; + VcodecExtraInfo *extra = &send_cfg->extra_info; + VcodecExtraSlot *slot = &extra->slots[extra->count]; + + slot->reg_idx = cfg->reg_idx; + slot->offset = cfg->offset; + extra->count++; + } + + return MPP_OK; +} + +MPP_RET vcodec_service_cmd_send(void *ctx) +{ + MppDevVcodecService *p = (MppDevVcodecService *)ctx; + VcodecRegCfg *send_cfg = &p->regs[p->reg_send_idx]; + VcodecExtraInfo *extra = &send_cfg->extra_info; + void *reg_set = send_cfg->reg_set; + RK_U32 reg_size = send_cfg->reg_size; + + if (extra->count) { + void *extra_data = reg_set + reg_size; + RK_S32 extra_size = sizeof(send_cfg->extra_info); + + memcpy(extra_data, extra, extra_size); + reg_size += extra_size; + + extra_info_init(extra); + } + + MPP_RET ret = vcodec_service_ioctl(p->fd, VPU_IOC_SET_REG, + reg_set, reg_size); + if (ret) { + mpp_err_f("ioctl VPU_IOC_SET_REG failed ret %d errno %d %s\n", + ret, errno, strerror(errno)); + ret = errno; + } + + p->reg_send_idx++; + if (p->reg_send_idx >= p->max_regs) + p->reg_send_idx = 0; + + return ret; +} + +MPP_RET vcodec_service_cmd_poll(void *ctx) +{ + MppDevVcodecService *p = (MppDevVcodecService *)ctx; + VcodecRegCfg *poll_cfg = &p->regs[p->reg_poll_idx]; + void *reg_get = poll_cfg->reg_get; + RK_S32 reg_size = poll_cfg->reg_size; + MPP_RET ret = vcodec_service_ioctl(p->fd, VPU_IOC_GET_REG, + reg_get, reg_size); + if (ret) { + mpp_err_f("ioctl VPU_IOC_GET_REG failed ret %d errno %d %s\n", + ret, errno, strerror(errno)); + ret = errno; + } + + p->reg_poll_idx++; + if (p->reg_poll_idx >= p->max_regs) + p->reg_poll_idx = 0; + + return ret; +} + +const MppDevApi vcodec_service_api = { + "vcodec_service", + sizeof(MppDevVcodecService), + vcodec_service_init, + vcodec_service_deinit, + vcodec_service_reg_wr, + vcodec_service_reg_rd, + vcodec_service_fd_trans, + NULL, + vcodec_service_cmd_send, + vcodec_service_cmd_poll, +}; diff --git a/osal/inc/mpp_device_api.h b/osal/inc/mpp_device_api.h new file mode 100644 index 00000000..45af4402 --- /dev/null +++ b/osal/inc/mpp_device_api.h @@ -0,0 +1,98 @@ +/* + * Copyright 2020 Rockchip Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MPP_DEVICE_API_H__ +#define __MPP_DEVICE_API_H__ + +#include "rk_type.h" +#include "mpp_err.h" +#include "mpp_platform.h" + +typedef enum MppDevIoctlCmd_e { + /* hardware operation setup config */ + MPP_DEV_REG_WR, + MPP_DEV_REG_RD, + MPP_DEV_FD_TRANS, + MPP_DEV_SET_INFO, + + MPP_DEV_CMD_SEND, + MPP_DEV_CMD_POLL, + + MPP_DEV_IOCTL_CMD_BUTT, +} MppDevIoctlCmd; + +/* for MPP_DEV_REG_WR */ +typedef struct MppDevRegWrCfg_t { + void *reg; + RK_U32 size; + RK_U32 offset; +} MppDevRegWrCfg; + +/* for MPP_DEV_REG_RD */ +typedef struct MppDevRegRdCfg_t { + void *reg; + RK_U32 size; + RK_U32 offset; +} MppDevRegRdCfg; + +/* for MPP_DEV_FD_TRANS */ +typedef struct MppDevFdTransCfg_t { + RK_U32 reg_idx; + RK_U32 offset; +} MppDevFdTransCfg; + +/* for MPP_DEV_SET_INFO */ +typedef struct MppDevSetInfoCfg_t { + RK_U32 type; + RK_U32 flag; + RK_U64 data; +} MppDevSetInfoCfg; + +typedef struct MppDevApi_t { + const char *name; + RK_U32 ctx_size; + MPP_RET (*init)(void *ctx, MppClientType type); + MPP_RET (*deinit)(void *ctx); + + /* config the cmd on preparing */ + MPP_RET (*reg_wr)(void *ctx, MppDevRegWrCfg *cfg); + MPP_RET (*reg_rd)(void *ctx, MppDevRegRdCfg *cfg); + MPP_RET (*fd_trans)(void *ctx, MppDevFdTransCfg *cfg); + MPP_RET (*set_info)(void *ctx, MppDevSetInfoCfg *cfg); + + /* send cmd to hardware */ + MPP_RET (*cmd_send)(void *ctx); + + /* poll cmd from hardware */ + MPP_RET (*cmd_poll)(void *ctx); +} MppDevApi; + +typedef void* MppDev; + +#ifdef __cplusplus +extern "C" { +#endif + +MPP_RET mpp_dev_init(MppDev *ctx, MppClientType type); +MPP_RET mpp_dev_deinit(MppDev ctx); + +MPP_RET mpp_dev_ioctl(MppDev ctx, RK_S32 cmd, void *param); + +#ifdef __cplusplus +} +#endif + +#endif /* __MPP_DEVICE_API_H__ */ diff --git a/osal/inc/mpp_platform.h b/osal/inc/mpp_platform.h index cb6502d8..aaebe033 100644 --- a/osal/inc/mpp_platform.h +++ b/osal/inc/mpp_platform.h @@ -32,7 +32,7 @@ typedef enum MppIoctlVersion_e { /* * Platform video codec hardware feature */ -typedef enum { +typedef enum MppClientType_e { VPU_CLIENT_VDPU1 = 0, /* 0x00000001 */ VPU_CLIENT_VDPU2 = 1, /* 0x00000002 */ VPU_CLIENT_VDPU1_PP = 2, /* 0x00000004 */ @@ -51,7 +51,7 @@ typedef enum { IEP_CLIENT_TYPE = 28, /* 0x10000000 */ VPU_CLIENT_BUTT, -} VPU_CLIENT2_TYPE; +} MppClientType; /* RK combined codec */ #define HAVE_VDPU1 (1 << VPU_CLIENT_VDPU1) /* 0x00000001 */ @@ -94,14 +94,13 @@ MppIoctlVersion mpp_get_ioctl_version(void); const char *mpp_get_soc_name(void); RK_U32 mpp_get_vcodec_type(void); RK_U32 mpp_get_2d_hw_flag(void); -RK_U32 mpp_refresh_vcodec_type(RK_U32 vcodec_type); const char *mpp_get_platform_dev_name(MppCtxType type, MppCodingType coding, RK_U32 platform); const char *mpp_get_vcodec_dev_name(MppCtxType type, MppCodingType coding); const MppServiceCmdCap *mpp_get_mpp_service_cmd_cap(void); +RK_U32 mpp_get_client_hw_id(RK_S32 client_type); #ifdef __cplusplus } #endif #endif /*__MPP_PLATFORM__*/ - diff --git a/osal/inc/mpp_service.h b/osal/inc/mpp_service.h index 238a11f8..6f25f05a 100644 --- a/osal/inc/mpp_service.h +++ b/osal/inc/mpp_service.h @@ -56,7 +56,7 @@ typedef enum MppDevCmd_e { MPP_DEV_PROP_BUTT, } MppDevCmd; -typedef enum MppDevCmdType_e { +typedef enum MppServiceCmdType_e { MPP_CMD_QUERY_BASE = 0, MPP_CMD_PROBE_HW_SUPPORT = MPP_CMD_QUERY_BASE + 0, MPP_CMD_QUERY_HW_ID = MPP_CMD_QUERY_BASE + 1, @@ -87,7 +87,7 @@ typedef enum MppDevCmdType_e { MPP_CMD_CONTROL_BUTT, MPP_CMD_BUTT, -} MppDevCmdType; +} MppServiceCmdType; typedef struct MppReq_t { RK_U32 *req; @@ -111,4 +111,14 @@ typedef struct MppServiceCmdCap_t { RK_U32 ctrl_cmd; } MppServiceCmdCap; +#ifdef __cplusplus +extern "C" { +#endif + +void check_mpp_service_cap(RK_U32 *codec_type, RK_U32 *hw_ids, MppServiceCmdCap *cap); + +#ifdef __cplusplus +} +#endif + #endif /* __MPP_SERVICE_H__ */ diff --git a/osal/inc/mpp_service_api.h b/osal/inc/mpp_service_api.h new file mode 100644 index 00000000..97da186a --- /dev/null +++ b/osal/inc/mpp_service_api.h @@ -0,0 +1,32 @@ +/* + * Copyright 2020 Rockchip Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MPP_SERVICE_API_H__ +#define __MPP_SERVICE_API_H__ + +#include "mpp_device_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const MppDevApi mpp_service_api; + +#ifdef __cplusplus +} +#endif + +#endif /* __MPP_SERVICE_API_H__ */ diff --git a/osal/inc/vcodec_service.h b/osal/inc/vcodec_service.h index f7a33aae..7178fe05 100644 --- a/osal/inc/vcodec_service.h +++ b/osal/inc/vcodec_service.h @@ -32,6 +32,18 @@ #define VPU_IOC_WRITE(nr, size) _IOC(_IOC_WRITE, VPU_IOC_MAGIC, (nr), (size)) +#define VDPU1_REGISTERS (101) +#define VDPU2_REGISTERS (159) +#define VDPU1_PP_REGISTERS (164) +#define VDPU2_PP_REGISTERS (184) +#define RKHEVC_REGISTERS (68) +#define RKVDEC_REGISTERS (78) +#define AVSD_REGISTERS (60) + +#define VEPU1_REGISTERS (164) +#define VEPU2_REGISTERS (184) +#define RKVENC_REGISTERS (140) + typedef struct VPUReq { RK_U32 *req; RK_U32 size; diff --git a/osal/inc/vcodec_service_api.h b/osal/inc/vcodec_service_api.h new file mode 100644 index 00000000..c2584a21 --- /dev/null +++ b/osal/inc/vcodec_service_api.h @@ -0,0 +1,32 @@ +/* + * Copyright 2020 Rockchip Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __VCODEC_SERVICE_API_H__ +#define __VCODEC_SERVICE_API_H__ + +#include "mpp_device_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const MppDevApi vcodec_service_api; + +#ifdef __cplusplus +} +#endif + +#endif /* __VCODEC_SERVICE_API_H__ */ diff --git a/osal/mpp_platform.cpp b/osal/mpp_platform.cpp index 1fed3aef..1937e0b2 100644 --- a/osal/mpp_platform.cpp +++ b/osal/mpp_platform.cpp @@ -194,7 +194,7 @@ private: MppIoctlVersion ioctl_version; RK_U32 vcodec_type; - RK_U32 vcodec_capability; + RK_U32 hw_ids[32]; MppServiceCmdCap mpp_service_cmd_cap; char soc_name[MAX_SOC_NAME_LENGTH]; RockchipSocType soc_type; @@ -209,9 +209,8 @@ public: const char *get_soc_name() { return soc_name; }; RockchipSocType get_soc_type() { return soc_type; }; RK_U32 get_vcodec_type() { return vcodec_type; }; - void set_vcodec_type(RK_U32 val) { vcodec_type = val; }; - RK_U32 get_vcodec_capability() { return vcodec_capability; }; MppServiceCmdCap *get_mpp_service_cmd_cap() { return &mpp_service_cmd_cap; }; + RK_U32 get_hw_id(RK_S32 client_type); }; MppPlatformService::MppPlatformService() @@ -248,6 +247,7 @@ MppPlatformService::MppPlatformService() /* if /dev/mpp_service not double check */ if (mpp_find_device(mpp_service_dev)) { ioctl_version = IOCTL_MPP_SERVICE_V1; + check_mpp_service_cap(&vcodec_type, hw_ids, cap); mpp_dbg(MPP_DBG_PLATFORM, "/dev/mpp_service not double check device\n"); goto __return; } @@ -301,6 +301,16 @@ __return: mpp_dbg(MPP_DBG_PLATFORM, "vcodec type %08x\n", vcodec_type); } +RK_U32 MppPlatformService::get_hw_id(RK_S32 client_type) +{ + RK_U32 hw_id = 0; + + if (vcodec_type & (1 << client_type)) + hw_id = hw_ids[client_type]; + + return hw_id; +} + MppIoctlVersion mpp_get_ioctl_version(void) { return MppPlatformService::get_instance()->get_ioctl_version(); @@ -340,13 +350,6 @@ RK_U32 mpp_get_2d_hw_flag(void) return flag; } -RK_U32 mpp_refresh_vcodec_type(RK_U32 vcodec_type) -{ - MppPlatformService::get_instance()->set_vcodec_type(vcodec_type); - - return 0; -} - const char *mpp_get_platform_dev_name(MppCtxType type, MppCodingType coding, RK_U32 platform) { const char *dev = mpp_find_device(mpp_service_dev); @@ -558,3 +561,8 @@ const MppServiceCmdCap *mpp_get_mpp_service_cmd_cap(void) { return MppPlatformService::get_instance()->get_mpp_service_cmd_cap(); } + +RK_U32 mpp_get_client_hw_id(RK_S32 client_type) +{ + return MppPlatformService::get_instance()->get_hw_id(client_type); +}