1 /*
2  * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
3  * Copyright (C) 2017 Linaro Ltd.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 and
7  * only version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  */
15 #include <linux/slab.h>
16 #include <linux/mutex.h>
17 #include <linux/list.h>
18 #include <linux/completion.h>
19 #include <linux/platform_device.h>
20 #include <linux/videodev2.h>
21 
22 #include "core.h"
23 #include "hfi.h"
24 #include "hfi_cmds.h"
25 #include "hfi_venus.h"
26 
27 #define TIMEOUT		msecs_to_jiffies(1000)
28 
29 static u32 to_codec_type(u32 pixfmt)
30 {
31 	switch (pixfmt) {
32 	case V4L2_PIX_FMT_H264:
33 	case V4L2_PIX_FMT_H264_NO_SC:
34 		return HFI_VIDEO_CODEC_H264;
35 	case V4L2_PIX_FMT_H263:
36 		return HFI_VIDEO_CODEC_H263;
37 	case V4L2_PIX_FMT_MPEG1:
38 		return HFI_VIDEO_CODEC_MPEG1;
39 	case V4L2_PIX_FMT_MPEG2:
40 		return HFI_VIDEO_CODEC_MPEG2;
41 	case V4L2_PIX_FMT_MPEG4:
42 		return HFI_VIDEO_CODEC_MPEG4;
43 	case V4L2_PIX_FMT_VC1_ANNEX_G:
44 	case V4L2_PIX_FMT_VC1_ANNEX_L:
45 		return HFI_VIDEO_CODEC_VC1;
46 	case V4L2_PIX_FMT_VP8:
47 		return HFI_VIDEO_CODEC_VP8;
48 	case V4L2_PIX_FMT_VP9:
49 		return HFI_VIDEO_CODEC_VP9;
50 	case V4L2_PIX_FMT_XVID:
51 		return HFI_VIDEO_CODEC_DIVX;
52 	case V4L2_PIX_FMT_HEVC:
53 		return HFI_VIDEO_CODEC_HEVC;
54 	default:
55 		return 0;
56 	}
57 }
58 
59 int hfi_core_init(struct venus_core *core)
60 {
61 	int ret = 0;
62 
63 	mutex_lock(&core->lock);
64 
65 	if (core->state >= CORE_INIT)
66 		goto unlock;
67 
68 	reinit_completion(&core->done);
69 
70 	ret = core->ops->core_init(core);
71 	if (ret)
72 		goto unlock;
73 
74 	ret = wait_for_completion_timeout(&core->done, TIMEOUT);
75 	if (!ret) {
76 		ret = -ETIMEDOUT;
77 		goto unlock;
78 	}
79 
80 	ret = 0;
81 
82 	if (core->error != HFI_ERR_NONE) {
83 		ret = -EIO;
84 		goto unlock;
85 	}
86 
87 	core->state = CORE_INIT;
88 unlock:
89 	mutex_unlock(&core->lock);
90 	return ret;
91 }
92 
93 int hfi_core_deinit(struct venus_core *core, bool blocking)
94 {
95 	int ret = 0, empty;
96 
97 	mutex_lock(&core->lock);
98 
99 	if (core->state == CORE_UNINIT)
100 		goto unlock;
101 
102 	empty = list_empty(&core->instances);
103 
104 	if (!empty && !blocking) {
105 		ret = -EBUSY;
106 		goto unlock;
107 	}
108 
109 	if (!empty) {
110 		mutex_unlock(&core->lock);
111 		wait_var_event(&core->insts_count,
112 			       !atomic_read(&core->insts_count));
113 		mutex_lock(&core->lock);
114 	}
115 
116 	ret = core->ops->core_deinit(core);
117 
118 	if (!ret)
119 		core->state = CORE_UNINIT;
120 
121 unlock:
122 	mutex_unlock(&core->lock);
123 	return ret;
124 }
125 
126 int hfi_core_suspend(struct venus_core *core)
127 {
128 	if (core->state != CORE_INIT)
129 		return 0;
130 
131 	return core->ops->suspend(core);
132 }
133 
134 int hfi_core_resume(struct venus_core *core, bool force)
135 {
136 	if (!force && core->state != CORE_INIT)
137 		return 0;
138 
139 	return core->ops->resume(core);
140 }
141 
142 int hfi_core_trigger_ssr(struct venus_core *core, u32 type)
143 {
144 	return core->ops->core_trigger_ssr(core, type);
145 }
146 
147 int hfi_core_ping(struct venus_core *core)
148 {
149 	int ret;
150 
151 	mutex_lock(&core->lock);
152 
153 	ret = core->ops->core_ping(core, 0xbeef);
154 	if (ret)
155 		goto unlock;
156 
157 	ret = wait_for_completion_timeout(&core->done, TIMEOUT);
158 	if (!ret) {
159 		ret = -ETIMEDOUT;
160 		goto unlock;
161 	}
162 	ret = 0;
163 	if (core->error != HFI_ERR_NONE)
164 		ret = -ENODEV;
165 unlock:
166 	mutex_unlock(&core->lock);
167 	return ret;
168 }
169 
170 static int wait_session_msg(struct venus_inst *inst)
171 {
172 	int ret;
173 
174 	ret = wait_for_completion_timeout(&inst->done, TIMEOUT);
175 	if (!ret)
176 		return -ETIMEDOUT;
177 
178 	if (inst->error != HFI_ERR_NONE)
179 		return -EIO;
180 
181 	return 0;
182 }
183 
184 int hfi_session_create(struct venus_inst *inst, const struct hfi_inst_ops *ops)
185 {
186 	struct venus_core *core = inst->core;
187 
188 	if (!ops)
189 		return -EINVAL;
190 
191 	inst->state = INST_UNINIT;
192 	init_completion(&inst->done);
193 	inst->ops = ops;
194 
195 	mutex_lock(&core->lock);
196 	list_add_tail(&inst->list, &core->instances);
197 	atomic_inc(&core->insts_count);
198 	mutex_unlock(&core->lock);
199 
200 	return 0;
201 }
202 EXPORT_SYMBOL_GPL(hfi_session_create);
203 
204 int hfi_session_init(struct venus_inst *inst, u32 pixfmt)
205 {
206 	struct venus_core *core = inst->core;
207 	const struct hfi_ops *ops = core->ops;
208 	int ret;
209 
210 	inst->hfi_codec = to_codec_type(pixfmt);
211 	reinit_completion(&inst->done);
212 
213 	ret = ops->session_init(inst, inst->session_type, inst->hfi_codec);
214 	if (ret)
215 		return ret;
216 
217 	ret = wait_session_msg(inst);
218 	if (ret)
219 		return ret;
220 
221 	inst->state = INST_INIT;
222 
223 	return 0;
224 }
225 EXPORT_SYMBOL_GPL(hfi_session_init);
226 
227 void hfi_session_destroy(struct venus_inst *inst)
228 {
229 	struct venus_core *core = inst->core;
230 
231 	mutex_lock(&core->lock);
232 	list_del_init(&inst->list);
233 	if (atomic_dec_and_test(&core->insts_count))
234 		wake_up_var(&core->insts_count);
235 	mutex_unlock(&core->lock);
236 }
237 EXPORT_SYMBOL_GPL(hfi_session_destroy);
238 
239 int hfi_session_deinit(struct venus_inst *inst)
240 {
241 	const struct hfi_ops *ops = inst->core->ops;
242 	int ret;
243 
244 	if (inst->state == INST_UNINIT)
245 		return 0;
246 
247 	if (inst->state < INST_INIT)
248 		return -EINVAL;
249 
250 	reinit_completion(&inst->done);
251 
252 	ret = ops->session_end(inst);
253 	if (ret)
254 		return ret;
255 
256 	ret = wait_session_msg(inst);
257 	if (ret)
258 		return ret;
259 
260 	inst->state = INST_UNINIT;
261 
262 	return 0;
263 }
264 EXPORT_SYMBOL_GPL(hfi_session_deinit);
265 
266 int hfi_session_start(struct venus_inst *inst)
267 {
268 	const struct hfi_ops *ops = inst->core->ops;
269 	int ret;
270 
271 	if (inst->state != INST_LOAD_RESOURCES)
272 		return -EINVAL;
273 
274 	reinit_completion(&inst->done);
275 
276 	ret = ops->session_start(inst);
277 	if (ret)
278 		return ret;
279 
280 	ret = wait_session_msg(inst);
281 	if (ret)
282 		return ret;
283 
284 	inst->state = INST_START;
285 
286 	return 0;
287 }
288 
289 int hfi_session_stop(struct venus_inst *inst)
290 {
291 	const struct hfi_ops *ops = inst->core->ops;
292 	int ret;
293 
294 	if (inst->state != INST_START)
295 		return -EINVAL;
296 
297 	reinit_completion(&inst->done);
298 
299 	ret = ops->session_stop(inst);
300 	if (ret)
301 		return ret;
302 
303 	ret = wait_session_msg(inst);
304 	if (ret)
305 		return ret;
306 
307 	inst->state = INST_STOP;
308 
309 	return 0;
310 }
311 
312 int hfi_session_continue(struct venus_inst *inst)
313 {
314 	struct venus_core *core = inst->core;
315 
316 	if (core->res->hfi_version == HFI_VERSION_1XX)
317 		return 0;
318 
319 	return core->ops->session_continue(inst);
320 }
321 EXPORT_SYMBOL_GPL(hfi_session_continue);
322 
323 int hfi_session_abort(struct venus_inst *inst)
324 {
325 	const struct hfi_ops *ops = inst->core->ops;
326 	int ret;
327 
328 	reinit_completion(&inst->done);
329 
330 	ret = ops->session_abort(inst);
331 	if (ret)
332 		return ret;
333 
334 	ret = wait_session_msg(inst);
335 	if (ret)
336 		return ret;
337 
338 	return 0;
339 }
340 
341 int hfi_session_load_res(struct venus_inst *inst)
342 {
343 	const struct hfi_ops *ops = inst->core->ops;
344 	int ret;
345 
346 	if (inst->state != INST_INIT)
347 		return -EINVAL;
348 
349 	reinit_completion(&inst->done);
350 
351 	ret = ops->session_load_res(inst);
352 	if (ret)
353 		return ret;
354 
355 	ret = wait_session_msg(inst);
356 	if (ret)
357 		return ret;
358 
359 	inst->state = INST_LOAD_RESOURCES;
360 
361 	return 0;
362 }
363 
364 int hfi_session_unload_res(struct venus_inst *inst)
365 {
366 	const struct hfi_ops *ops = inst->core->ops;
367 	int ret;
368 
369 	if (inst->state != INST_STOP)
370 		return -EINVAL;
371 
372 	reinit_completion(&inst->done);
373 
374 	ret = ops->session_release_res(inst);
375 	if (ret)
376 		return ret;
377 
378 	ret = wait_session_msg(inst);
379 	if (ret)
380 		return ret;
381 
382 	inst->state = INST_RELEASE_RESOURCES;
383 
384 	return 0;
385 }
386 
387 int hfi_session_flush(struct venus_inst *inst)
388 {
389 	const struct hfi_ops *ops = inst->core->ops;
390 	int ret;
391 
392 	reinit_completion(&inst->done);
393 
394 	ret = ops->session_flush(inst, HFI_FLUSH_ALL);
395 	if (ret)
396 		return ret;
397 
398 	ret = wait_session_msg(inst);
399 	if (ret)
400 		return ret;
401 
402 	return 0;
403 }
404 EXPORT_SYMBOL_GPL(hfi_session_flush);
405 
406 int hfi_session_set_buffers(struct venus_inst *inst, struct hfi_buffer_desc *bd)
407 {
408 	const struct hfi_ops *ops = inst->core->ops;
409 
410 	return ops->session_set_buffers(inst, bd);
411 }
412 
413 int hfi_session_unset_buffers(struct venus_inst *inst,
414 			      struct hfi_buffer_desc *bd)
415 {
416 	const struct hfi_ops *ops = inst->core->ops;
417 	int ret;
418 
419 	reinit_completion(&inst->done);
420 
421 	ret = ops->session_unset_buffers(inst, bd);
422 	if (ret)
423 		return ret;
424 
425 	if (!bd->response_required)
426 		return 0;
427 
428 	ret = wait_session_msg(inst);
429 	if (ret)
430 		return ret;
431 
432 	return 0;
433 }
434 
435 int hfi_session_get_property(struct venus_inst *inst, u32 ptype,
436 			     union hfi_get_property *hprop)
437 {
438 	const struct hfi_ops *ops = inst->core->ops;
439 	int ret;
440 
441 	if (inst->state < INST_INIT || inst->state >= INST_STOP)
442 		return -EINVAL;
443 
444 	reinit_completion(&inst->done);
445 
446 	ret = ops->session_get_property(inst, ptype);
447 	if (ret)
448 		return ret;
449 
450 	ret = wait_session_msg(inst);
451 	if (ret)
452 		return ret;
453 
454 	*hprop = inst->hprop;
455 
456 	return 0;
457 }
458 EXPORT_SYMBOL_GPL(hfi_session_get_property);
459 
460 int hfi_session_set_property(struct venus_inst *inst, u32 ptype, void *pdata)
461 {
462 	const struct hfi_ops *ops = inst->core->ops;
463 
464 	if (inst->state < INST_INIT || inst->state >= INST_STOP)
465 		return -EINVAL;
466 
467 	return ops->session_set_property(inst, ptype, pdata);
468 }
469 EXPORT_SYMBOL_GPL(hfi_session_set_property);
470 
471 int hfi_session_process_buf(struct venus_inst *inst, struct hfi_frame_data *fd)
472 {
473 	const struct hfi_ops *ops = inst->core->ops;
474 
475 	if (fd->buffer_type == HFI_BUFFER_INPUT)
476 		return ops->session_etb(inst, fd);
477 	else if (fd->buffer_type == HFI_BUFFER_OUTPUT ||
478 		 fd->buffer_type == HFI_BUFFER_OUTPUT2)
479 		return ops->session_ftb(inst, fd);
480 
481 	return -EINVAL;
482 }
483 EXPORT_SYMBOL_GPL(hfi_session_process_buf);
484 
485 irqreturn_t hfi_isr_thread(int irq, void *dev_id)
486 {
487 	struct venus_core *core = dev_id;
488 
489 	return core->ops->isr_thread(core);
490 }
491 
492 irqreturn_t hfi_isr(int irq, void *dev)
493 {
494 	struct venus_core *core = dev;
495 
496 	return core->ops->isr(core);
497 }
498 
499 int hfi_create(struct venus_core *core, const struct hfi_core_ops *ops)
500 {
501 	int ret;
502 
503 	if (!ops)
504 		return -EINVAL;
505 
506 	atomic_set(&core->insts_count, 0);
507 	core->core_ops = ops;
508 	core->state = CORE_UNINIT;
509 	init_completion(&core->done);
510 	pkt_set_version(core->res->hfi_version);
511 	ret = venus_hfi_create(core);
512 
513 	return ret;
514 }
515 
516 void hfi_destroy(struct venus_core *core)
517 {
518 	venus_hfi_destroy(core);
519 }
520