1 /*
2 *
3 * Copyright 2015 Rockchip Electronics Co., LTD.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #define MODULE_TAG "vpu"
19
20 #include "vpu.h"
21 #include <sys/ioctl.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <string.h>
25 #include "hdf_log.h"
26 #include "rk_mpi.h"
27 #include "securec.h"
28 #include "mpp_env.h"
29 #include "mpp_common.h"
30 #include "mpp_platform.h"
31 #include "mpp_service.h"
32 #include "vcodec_service.h"
33 #include "vpu_mem_legacy.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 = (*(mRKMppApi.Hdimpp_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 HDF_LOGE("can not find valid client type ioctl\n");
105 } else {
106 RK_U32 cmd = (vpu_api_ioctl_version == 0) ?
107 (VPU_IOC_SET_CLIENT_TYPE) :
108 (VPU_IOC_SET_CLIENT_TYPE_U32);
109
110 ret = ioctl(dev, cmd, client_type);
111 }
112 }
113
114 if (ret)
115 HDF_LOGE("set client type failed ret %d errno %d\n", ret, errno);
116
117 return ret;
118 }
119
120
VPUClientInit(VPU_CLIENT_TYPE type)121 int VPUClientInit(VPU_CLIENT_TYPE type)
122 {
123 int ret;
124 int fd;
125 const char *path;
126 MppCtxType ctx_type;
127 MppCodingType coding = MPP_VIDEO_CodingAutoDetect;
128
129 switch (type) {
130 case VPU_DEC_HEVC:
131 coding = MPP_VIDEO_CodingHEVC;
132 ctx_type = MPP_CTX_DEC;
133 type = VPU_DEC;
134 break;
135 case VPU_DEC_AVS:
136 coding = MPP_VIDEO_CodingAVS;
137 ctx_type = MPP_CTX_DEC;
138 type = VPU_DEC;
139 break;
140 case VPU_DEC_RKV:
141 type = VPU_DEC;
142 ctx_type = MPP_CTX_DEC;
143 break;
144 case VPU_DEC:
145 case VPU_DEC_PP:
146 case VPU_PP:
147 ctx_type = MPP_CTX_DEC;
148 break;
149 case VPU_ENC:
150 case VPU_ENC_RKV:
151 ctx_type = MPP_CTX_ENC;
152 break;
153 default:
154 return -1;
155 break;
156 }
157
158 path = (*(mRKMppApi.Hdimpp_get_vcodec_dev_name))(ctx_type, coding);
159 fd = open(path, O_RDWR | O_CLOEXEC);
160
161 (*(mRKMppApi.HdiMppEnvGetU32))("vpu_debug", &vpu_debug, 0);
162
163 ioctl_version = (*(mRKMppApi.Hdimpp_get_ioctl_version))();
164
165 if (fd == -1) {
166 HDF_LOGE("failed to open %s, errno = %d, error msg: %s\n", \
167 path, errno, strerror(errno));
168 return -1;
169 }
170
171 ret = vpu_api_set_client_type(fd, type);
172 if (ret) {
173 return -2; // return -2
174 }
175
176 return fd;
177 }
178
VPUClientRelease(int socket)179 RK_S32 VPUClientRelease(int socket)
180 {
181 int fd = socket;
182 if (fd > 0) {
183 close(fd);
184 }
185 return VPU_SUCCESS;
186 }
187
VPUClientSendReg(int socket,RK_U32 * regs,RK_U32 nregs)188 RK_S32 VPUClientSendReg(int socket, RK_U32 *regs, RK_U32 nregs)
189 {
190 int fd = socket;
191 RK_S32 ret;
192 VPUReq_t req;
193
194 if (vpu_debug) {
195 RK_U32 i;
196
197 for (i = 0; i < nregs; i++)
198 HDF_LOGE("set reg[%03d]: %08x\n", i, regs[i]);
199 }
200
201 if (ioctl_version > 0) {
202 MppReqV1 reqs[3];
203 RK_U32 reg_size = nregs;
204
205 VpuExtraInfo *extra_info = (VpuExtraInfo*)(regs + (nregs - VPU_EXTRA_INFO_SIZE));
206
207 reqs[0].cmd = MPP_CMD_SET_REG_WRITE;
208 reqs[0].flag = 0;
209 reqs[0].offset = 0;
210 reqs[0].size = reg_size * sizeof(RK_U32);
211 reqs[0].data_ptr = REQ_DATA_PTR((void*)regs);
212 reqs[0].flag |= VPU_MPP_FLAGS_MULTI_MSG;
213
214 reqs[1].cmd = MPP_CMD_SET_REG_READ;
215 reqs[1].flag = 0;
216 reqs[1].offset = 0;
217 reqs[1].size = reg_size * sizeof(RK_U32);
218 reqs[1].data_ptr = REQ_DATA_PTR((void*)regs);
219
220 if (extra_info && extra_info->magic == VPU_EXTRA_INFO_MAGIC) {
221 reg_size = nregs - VPU_EXTRA_INFO_SIZE;
222 reqs[2].cmd = MPP_CMD_SET_REG_ADDR_OFFSET; // reqs[2]
223 reqs[2].flag = 0; // reqs[2]
224 reqs[2].offset = 0; // reqs[2]
225 reqs[2].size = extra_info->count * sizeof(extra_info->patchs[0]); // reqs[2]
226 reqs[2].data_ptr = REQ_DATA_PTR((void *)&extra_info->patchs[0]); // reqs[2]
227
228 reqs[0].size = reg_size * sizeof(RK_U32);
229 reqs[1].size = reg_size * sizeof(RK_U32);
230 reqs[1].flag |= VPU_MPP_FLAGS_MULTI_MSG;
231 reqs[2].flag |= VPU_MPP_FLAGS_LAST_MSG; // reqs[2]
232 ret = (RK_S32)ioctl(fd, MPP_IOC_CFG_V1, &reqs);
233 } else {
234 MppReqV1 reqs_tmp[2];
235 reqs[1].flag |= VPU_MPP_FLAGS_LAST_MSG;
236 if (memcpy_s(reqs_tmp, sizeof(MppReqV1) * 2, reqs, sizeof(MppReqV1) * 2) != EOK) { // reqs[2]
237 HDF_LOGE("memcpy_s no");
238 }
239 ret = (RK_S32)ioctl(fd, MPP_IOC_CFG_V1, &reqs_tmp);
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 HDF_LOGE("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 HDF_LOGE("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 HDF_LOGE("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; // 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 HDF_LOGE("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 HDF_LOGE("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 HDF_LOGE("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_s(&hwCfg, sizeof(VPUHwDecConfig_t), 0, sizeof(VPUHwDecConfig_t));
342 if (fd >= 0) {
343 if (VPUClientGetHwCfg(fd, (RK_U32*)&hwCfg, sizeof(hwCfg))) {
344 HDF_LOGE("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