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