xref: /rockchip-linux_mpp/mpp/legacy/vpu.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
1 /*
2  * Copyright 2015 Rockchip Electronics Co. LTD
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define MODULE_TAG "vpu"
18 
19 #include <sys/ioctl.h>
20 #include <errno.h>
21 #include <string.h>
22 
23 #include "vpu.h"
24 #include "rk_mpi.h"
25 
26 #include "mpp_env.h"
27 #include "mpp_debug.h"
28 #include "mpp_common.h"
29 #include "mpp_platform.h"
30 
31 #include "mpp_service.h"
32 #include "vcodec_service.h"
33 
34 #define VPU_EXTRA_INFO_SIZE                 12
35 #define VPU_EXTRA_INFO_MAGIC                (0x4C4A46)
36 #define VPU_MPP_FLAGS_MULTI_MSG             (0x00000001)
37 #define VPU_MPP_FLAGS_LAST_MSG              (0x00000002)
38 
39 #define MPX_PATCH_NUM       16
40 
41 typedef struct VpuPatchInfo_t {
42     RK_U32          reg_idx;
43     RK_U32          offset;
44 } VpuPatchInfo;
45 
46 typedef struct VpuExtraInfo_t {
47     RK_U32          magic;      // Fix magic value 0x4C4A46
48     RK_U32          count;      // valid patch info count
49     VpuPatchInfo    patchs[MPX_PATCH_NUM];
50 } VpuExtraInfo;
51 
52 typedef struct VPUReq {
53     RK_U32 *req;
54     RK_U32  size;
55 } VPUReq_t;
56 
57 static RK_U32 vpu_debug = 0;
58 
59 /* 0 original version,  > 1 for others version */
60 static RK_S32 ioctl_version = 0;
61 
vpu_api_set_client_type(int dev,RK_S32 client_type)62 static RK_S32 vpu_api_set_client_type(int dev, RK_S32 client_type)
63 {
64     static RK_S32 vpu_api_ioctl_version = -1;
65     RK_S32 ret;
66 
67     if (ioctl_version > 0) {
68         MppReqV1 mpp_req;
69         RK_U32 vcodec_type;
70         RK_U32 client_data;
71 
72         vcodec_type = mpp_get_vcodec_type();
73 
74         switch (client_type) {
75         case VPU_ENC:
76             if (vcodec_type & HAVE_VDPU1)
77                 client_data = VPU_CLIENT_VEPU1;
78             else if (vcodec_type & HAVE_VDPU2)
79                 client_data = VPU_CLIENT_VEPU2;
80             break;
81         default:
82             break;
83         }
84 
85         mpp_req.cmd = MPP_CMD_INIT_CLIENT_TYPE;
86         mpp_req.flag = 0;
87         mpp_req.size = sizeof(client_data);
88         mpp_req.offset = 0;
89         mpp_req.data_ptr = REQ_DATA_PTR(&client_data);
90         ret = (RK_S32)ioctl(dev, MPP_IOC_CFG_V1, &mpp_req);
91     } else {
92         if (vpu_api_ioctl_version < 0) {
93             ret = ioctl(dev, VPU_IOC_SET_CLIENT_TYPE, client_type);
94             if (!ret) {
95                 vpu_api_ioctl_version = 0;
96             } else {
97                 ret = ioctl(dev, VPU_IOC_SET_CLIENT_TYPE_U32, client_type);
98                 if (!ret)
99                     vpu_api_ioctl_version = 1;
100             }
101 
102             if (ret)
103                 mpp_err_f("can not find valid client type ioctl\n");
104 
105             mpp_assert(ret == 0);
106         } else {
107             RK_U32 cmd = (vpu_api_ioctl_version == 0) ?
108                          (VPU_IOC_SET_CLIENT_TYPE) :
109                          (VPU_IOC_SET_CLIENT_TYPE_U32);
110 
111             ret = ioctl(dev, cmd, client_type);
112         }
113     }
114 
115     if (ret)
116         mpp_err_f("set client type failed ret %d errno %d\n", ret, errno);
117 
118     return ret;
119 }
120 
121 
VPUClientInit(VPU_CLIENT_TYPE type)122 int VPUClientInit(VPU_CLIENT_TYPE type)
123 {
124     int ret;
125     int fd;
126     const char *path;
127     MppCtxType ctx_type;
128     MppCodingType coding = MPP_VIDEO_CodingAutoDetect;
129 
130     switch (type) {
131     case VPU_DEC_HEVC:
132         coding = MPP_VIDEO_CodingHEVC;
133         ctx_type  = MPP_CTX_DEC;
134         type = VPU_DEC;
135         break;
136     case VPU_DEC_AVSPLUS:
137         coding = MPP_VIDEO_CodingAVSPLUS;
138         ctx_type  = MPP_CTX_DEC;
139         type = VPU_DEC;
140         break;
141     case VPU_DEC_RKV:
142         type = VPU_DEC;
143         ctx_type  = MPP_CTX_DEC;
144         break;
145     case VPU_DEC:
146     case VPU_DEC_PP:
147     case VPU_PP:
148         ctx_type  = MPP_CTX_DEC;
149         break;
150     case VPU_ENC:
151     case VPU_ENC_RKV:
152         ctx_type = MPP_CTX_ENC;
153         break;
154     default:
155         return -1;
156         break;
157     }
158 
159     path = mpp_get_vcodec_dev_name(ctx_type, coding);
160     fd = open(path, O_RDWR | O_CLOEXEC);
161 
162     mpp_env_get_u32("vpu_debug", &vpu_debug, 0);
163 
164     ioctl_version = mpp_get_ioctl_version();
165 
166     if (fd == -1) {
167         mpp_err_f("failed to open %s, errno = %d, error msg: %s\n",
168                   path, errno, strerror(errno));
169         return -1;
170     }
171 
172     ret = vpu_api_set_client_type(fd, type);
173     if (ret) {
174         return -2;
175     }
176 
177     return fd;
178 }
179 
VPUClientRelease(int socket)180 RK_S32 VPUClientRelease(int socket)
181 {
182     int fd = socket;
183     if (fd > 0) {
184         close(fd);
185     }
186     return VPU_SUCCESS;
187 }
188 
VPUClientSendReg(int socket,RK_U32 * regs,RK_U32 nregs)189 RK_S32 VPUClientSendReg(int socket, RK_U32 *regs, RK_U32 nregs)
190 {
191     int fd = socket;
192     RK_S32 ret;
193     VPUReq_t req;
194 
195     if (vpu_debug) {
196         RK_U32 i;
197 
198         for (i = 0; i < nregs; i++)
199             mpp_log("set reg[%03d]: %08x\n", i, regs[i]);
200     }
201 
202     if (ioctl_version > 0) {
203         MppReqV1 reqs[3];
204         RK_U32 reg_size = nregs;
205 
206         VpuExtraInfo *extra_info = (VpuExtraInfo*)(regs + (nregs - VPU_EXTRA_INFO_SIZE));
207 
208         reqs[0].cmd = MPP_CMD_SET_REG_WRITE;
209         reqs[0].flag = 0;
210         reqs[0].offset = 0;
211         reqs[0].size =  reg_size * sizeof(RK_U32);
212         reqs[0].data_ptr = REQ_DATA_PTR((void*)regs);
213         reqs[0].flag |= VPU_MPP_FLAGS_MULTI_MSG;
214 
215         reqs[1].cmd = MPP_CMD_SET_REG_READ;
216         reqs[1].flag = 0;
217         reqs[1].offset = 0;
218         reqs[1].size =  reg_size * sizeof(RK_U32);
219         reqs[1].data_ptr = REQ_DATA_PTR((void*)regs);
220 
221         if (extra_info && extra_info->magic == VPU_EXTRA_INFO_MAGIC) {
222             reg_size = nregs - VPU_EXTRA_INFO_SIZE;
223             reqs[2].cmd = MPP_CMD_SET_REG_ADDR_OFFSET;
224             reqs[2].flag = 0;
225             reqs[2].offset = 0;
226             reqs[2].size = extra_info->count * sizeof(extra_info->patchs[0]);
227             reqs[2].data_ptr = REQ_DATA_PTR((void *)&extra_info->patchs[0]);
228 
229             reqs[0].size =  reg_size * sizeof(RK_U32);
230             reqs[1].size =  reg_size * sizeof(RK_U32);
231             reqs[1].flag |= VPU_MPP_FLAGS_MULTI_MSG;
232             reqs[2].flag |= VPU_MPP_FLAGS_LAST_MSG;
233             ret = (RK_S32)ioctl(fd, MPP_IOC_CFG_V1, &reqs);
234         } else {
235             MppReqV1 reqs_tmp[2];
236             reqs[1].flag |= VPU_MPP_FLAGS_LAST_MSG;
237             memcpy(reqs_tmp, reqs, sizeof(MppReqV1) * 2);
238             ret = (RK_S32)ioctl(fd, MPP_IOC_CFG_V1, &reqs_tmp);
239         }
240 
241     } else {
242         nregs *= sizeof(RK_U32);
243         req.req     = regs;
244         req.size    = nregs;
245         ret = (RK_S32)ioctl(fd, VPU_IOC_SET_REG, &req);
246     }
247 
248     if (ret)
249         mpp_err_f("ioctl VPU_IOC_SET_REG failed ret %d errno %d %s\n", ret, errno, strerror(errno));
250 
251     return ret;
252 }
253 
VPUClientSendReg2(RK_S32 socket,RK_S32 offset,RK_S32 size,void * param)254 RK_S32 VPUClientSendReg2(RK_S32 socket, RK_S32 offset, RK_S32 size, void *param)
255 {
256     RK_S32 ret = 0;
257 
258     if (param == NULL) {
259         mpp_err_f("input param is NULL");
260         return 1;
261     }
262 
263     ret = (RK_S32)ioctl(socket, VPU_IOC_WRITE(offset, size), param);
264     if (ret)
265         mpp_err_f("ioctl VPU_IOC_WRITE failed ret %d", ret);
266 
267     return ret;
268 }
269 
VPUClientWaitResult(int socket,RK_U32 * regs,RK_U32 nregs,VPU_CMD_TYPE * cmd,RK_S32 * len)270 RK_S32 VPUClientWaitResult(int socket, RK_U32 *regs, RK_U32 nregs, VPU_CMD_TYPE *cmd, RK_S32 *len)
271 {
272     int fd = socket;
273     RK_S32 ret;
274     VPUReq_t req;
275     (void)len;
276 
277     if (ioctl_version > 0) {
278         MppReqV1 mpp_req;
279         RK_U32 reg_size = nregs;
280         VpuExtraInfo *extra_info = (VpuExtraInfo*)(regs + (nregs - VPU_EXTRA_INFO_SIZE));
281 
282         if (extra_info && extra_info->magic == VPU_EXTRA_INFO_MAGIC) {
283             reg_size -= 2;
284         } else {
285             reg_size -= VPU_EXTRA_INFO_SIZE;
286         }
287 
288         mpp_req.cmd = MPP_CMD_POLL_HW_FINISH;
289         mpp_req.flag = 0;
290         mpp_req.offset = 0;
291         mpp_req.size =  reg_size * sizeof(RK_U32);
292         mpp_req.data_ptr = REQ_DATA_PTR((void*)regs);
293         ret = (RK_S32)ioctl(fd, MPP_IOC_CFG_V1, &mpp_req);
294     } else {
295         nregs *= sizeof(RK_U32);
296         req.req     = regs;
297         req.size    = nregs;
298 
299         ret = (RK_S32)ioctl(fd, VPU_IOC_GET_REG, &req);
300     }
301 
302     if (ret) {
303         mpp_err_f("ioctl VPU_IOC_GET_REG failed ret %d errno %d %s\n", ret, errno, strerror(errno));
304         *cmd = VPU_SEND_CONFIG_ACK_FAIL;
305     } else
306         *cmd = VPU_SEND_CONFIG_ACK_OK;
307 
308     if (vpu_debug) {
309         RK_U32 i;
310 
311         for (i = 0; i < nregs; i++) {
312             mpp_log("get reg[%03d]: %08x\n", i, regs[i]);
313         }
314     }
315 
316     return ret;
317 }
318 
VPUClientGetHwCfg(int socket,RK_U32 * cfg,RK_U32 cfg_size)319 RK_S32 VPUClientGetHwCfg(int socket, RK_U32 *cfg, RK_U32 cfg_size)
320 {
321     int fd = socket;
322     RK_S32 ret;
323     VPUReq_t req;
324     req.req     = cfg;
325     req.size    = cfg_size;
326     ret = (RK_S32)ioctl(fd, VPU_IOC_GET_HW_FUSE_STATUS, &req);
327     if (ret)
328         mpp_err_f("ioctl VPU_IOC_GET_HW_FUSE_STATUS failed ret %d\n", ret);
329 
330     return ret;
331 }
332 
VPUCheckSupportWidth()333 RK_U32 VPUCheckSupportWidth()
334 {
335     VPUHwDecConfig_t hwCfg;
336     int fd = -1;
337     fd = open("/dev/vpu_service", O_RDWR | O_CLOEXEC);
338     if (fd < 0) {
339         fd = open("/dev/vpu-service", O_RDWR | O_CLOEXEC);
340     }
341     memset(&hwCfg, 0, sizeof(VPUHwDecConfig_t));
342     if (fd >= 0) {
343         if (VPUClientGetHwCfg(fd, (RK_U32*)&hwCfg, sizeof(hwCfg))) {
344             mpp_err_f("Get HwCfg failed\n");
345             close(fd);
346             return -1;
347         }
348         close(fd);
349         fd = -1;
350     }
351     return hwCfg.maxDecPicWidth;
352 }
353 
VPUClientGetIOMMUStatus()354 RK_S32 VPUClientGetIOMMUStatus()
355 {
356     return 1;
357 }
358