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