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 	default:
53 		return 0;
54 	}
55 }
56 
57 int hfi_core_init(struct venus_core *core)
58 {
59 	int ret = 0;
60 
61 	mutex_lock(&core->lock);
62 
63 	if (core->state >= CORE_INIT)
64 		goto unlock;
65 
66 	reinit_completion(&core->done);
67 
68 	ret = core->ops->core_init(core);
69 	if (ret)
70 		goto unlock;
71 
72 	ret = wait_for_completion_timeout(&core->done, TIMEOUT);
73 	if (!ret) {
74 		ret = -ETIMEDOUT;
75 		goto unlock;
76 	}
77 
78 	ret = 0;
79 
80 	if (core->error != HFI_ERR_NONE) {
81 		ret = -EIO;
82 		goto unlock;
83 	}
84 
85 	core->state = CORE_INIT;
86 unlock:
87 	mutex_unlock(&core->lock);
88 	return ret;
89 }
90 
91 static int core_deinit_wait_atomic_t(atomic_t *p)
92 {
93 	schedule();
94 	return 0;
95 }
96 
97 int hfi_core_deinit(struct venus_core *core, bool blocking)
98 {
99 	int ret = 0, empty;
100 
101 	mutex_lock(&core->lock);
102 
103 	if (core->state == CORE_UNINIT)
104 		goto unlock;
105 
106 	empty = list_empty(&core->instances);
107 
108 	if (!empty && !blocking) {
109 		ret = -EBUSY;
110 		goto unlock;
111 	}
112 
113 	if (!empty) {
114 		mutex_unlock(&core->lock);
115 		wait_on_atomic_t(&core->insts_count, core_deinit_wait_atomic_t,
116 				 TASK_UNINTERRUPTIBLE);
117 		mutex_lock(&core->lock);
118 	}
119 
120 	ret = core->ops->core_deinit(core);
121 
122 	if (!ret)
123 		core->state = CORE_UNINIT;
124 
125 unlock:
126 	mutex_unlock(&core->lock);
127 	return ret;
128 }
129 
130 int hfi_core_suspend(struct venus_core *core)
131 {
132 	if (core->state != CORE_INIT)
133 		return 0;
134 
135 	return core->ops->suspend(core);
136 }
137 
138 int hfi_core_resume(struct venus_core *core, bool force)
139 {
140 	if (!force && core->state != CORE_INIT)
141 		return 0;
142 
143 	return core->ops->resume(core);
144 }
145 
146 int hfi_core_trigger_ssr(struct venus_core *core, u32 type)
147 {
148 	return core->ops->core_trigger_ssr(core, type);
149 }
150 
151 int hfi_core_ping(struct venus_core *core)
152 {
153 	int ret;
154 
155 	mutex_lock(&core->lock);
156 
157 	ret = core->ops->core_ping(core, 0xbeef);
158 	if (ret)
159 		goto unlock;
160 
161 	ret = wait_for_completion_timeout(&core->done, TIMEOUT);
162 	if (!ret) {
163 		ret = -ETIMEDOUT;
164 		goto unlock;
165 	}
166 	ret = 0;
167 	if (core->error != HFI_ERR_NONE)
168 		ret = -ENODEV;
169 unlock:
170 	mutex_unlock(&core->lock);
171 	return ret;
172 }
173 
174 static int wait_session_msg(struct venus_inst *inst)
175 {
176 	int ret;
177 
178 	ret = wait_for_completion_timeout(&inst->done, TIMEOUT);
179 	if (!ret)
180 		return -ETIMEDOUT;
181 
182 	if (inst->error != HFI_ERR_NONE)
183 		return -EIO;
184 
185 	return 0;
186 }
187 
188 int hfi_session_create(struct venus_inst *inst, const struct hfi_inst_ops *ops)
189 {
190 	struct venus_core *core = inst->core;
191 
192 	if (!ops)
193 		return -EINVAL;
194 
195 	inst->state = INST_UNINIT;
196 	init_completion(&inst->done);
197 	inst->ops = ops;
198 
199 	mutex_lock(&core->lock);
200 	list_add_tail(&inst->list, &core->instances);
201 	atomic_inc(&core->insts_count);
202 	mutex_unlock(&core->lock);
203 
204 	return 0;
205 }
206 EXPORT_SYMBOL_GPL(hfi_session_create);
207 
208 int hfi_session_init(struct venus_inst *inst, u32 pixfmt)
209 {
210 	struct venus_core *core = inst->core;
211 	const struct hfi_ops *ops = core->ops;
212 	u32 codec;
213 	int ret;
214 
215 	codec = to_codec_type(pixfmt);
216 	reinit_completion(&inst->done);
217 
218 	ret = ops->session_init(inst, inst->session_type, codec);
219 	if (ret)
220 		return ret;
221 
222 	ret = wait_session_msg(inst);
223 	if (ret)
224 		return ret;
225 
226 	inst->state = INST_INIT;
227 
228 	return 0;
229 }
230 EXPORT_SYMBOL_GPL(hfi_session_init);
231 
232 void hfi_session_destroy(struct venus_inst *inst)
233 {
234 	struct venus_core *core = inst->core;
235 
236 	mutex_lock(&core->lock);
237 	list_del_init(&inst->list);
238 	atomic_dec(&core->insts_count);
239 	wake_up_atomic_t(&core->insts_count);
240 	mutex_unlock(&core->lock);
241 }
242 EXPORT_SYMBOL_GPL(hfi_session_destroy);
243 
244 int hfi_session_deinit(struct venus_inst *inst)
245 {
246 	const struct hfi_ops *ops = inst->core->ops;
247 	int ret;
248 
249 	if (inst->state == INST_UNINIT)
250 		return 0;
251 
252 	if (inst->state < INST_INIT)
253 		return -EINVAL;
254 
255 	reinit_completion(&inst->done);
256 
257 	ret = ops->session_end(inst);
258 	if (ret)
259 		return ret;
260 
261 	ret = wait_session_msg(inst);
262 	if (ret)
263 		return ret;
264 
265 	inst->state = INST_UNINIT;
266 
267 	return 0;
268 }
269 EXPORT_SYMBOL_GPL(hfi_session_deinit);
270 
271 int hfi_session_start(struct venus_inst *inst)
272 {
273 	const struct hfi_ops *ops = inst->core->ops;
274 	int ret;
275 
276 	if (inst->state != INST_LOAD_RESOURCES)
277 		return -EINVAL;
278 
279 	reinit_completion(&inst->done);
280 
281 	ret = ops->session_start(inst);
282 	if (ret)
283 		return ret;
284 
285 	ret = wait_session_msg(inst);
286 	if (ret)
287 		return ret;
288 
289 	inst->state = INST_START;
290 
291 	return 0;
292 }
293 
294 int hfi_session_stop(struct venus_inst *inst)
295 {
296 	const struct hfi_ops *ops = inst->core->ops;
297 	int ret;
298 
299 	if (inst->state != INST_START)
300 		return -EINVAL;
301 
302 	reinit_completion(&inst->done);
303 
304 	ret = ops->session_stop(inst);
305 	if (ret)
306 		return ret;
307 
308 	ret = wait_session_msg(inst);
309 	if (ret)
310 		return ret;
311 
312 	inst->state = INST_STOP;
313 
314 	return 0;
315 }
316 
317 int hfi_session_continue(struct venus_inst *inst)
318 {
319 	struct venus_core *core = inst->core;
320 
321 	if (core->res->hfi_version != HFI_VERSION_3XX)
322 		return 0;
323 
324 	return core->ops->session_continue(inst);
325 }
326 EXPORT_SYMBOL_GPL(hfi_session_continue);
327 
328 int hfi_session_abort(struct venus_inst *inst)
329 {
330 	const struct hfi_ops *ops = inst->core->ops;
331 	int ret;
332 
333 	reinit_completion(&inst->done);
334 
335 	ret = ops->session_abort(inst);
336 	if (ret)
337 		return ret;
338 
339 	ret = wait_session_msg(inst);
340 	if (ret)
341 		return ret;
342 
343 	return 0;
344 }
345 
346 int hfi_session_load_res(struct venus_inst *inst)
347 {
348 	const struct hfi_ops *ops = inst->core->ops;
349 	int ret;
350 
351 	if (inst->state != INST_INIT)
352 		return -EINVAL;
353 
354 	reinit_completion(&inst->done);
355 
356 	ret = ops->session_load_res(inst);
357 	if (ret)
358 		return ret;
359 
360 	ret = wait_session_msg(inst);
361 	if (ret)
362 		return ret;
363 
364 	inst->state = INST_LOAD_RESOURCES;
365 
366 	return 0;
367 }
368 
369 int hfi_session_unload_res(struct venus_inst *inst)
370 {
371 	const struct hfi_ops *ops = inst->core->ops;
372 	int ret;
373 
374 	if (inst->state != INST_STOP)
375 		return -EINVAL;
376 
377 	reinit_completion(&inst->done);
378 
379 	ret = ops->session_release_res(inst);
380 	if (ret)
381 		return ret;
382 
383 	ret = wait_session_msg(inst);
384 	if (ret)
385 		return ret;
386 
387 	inst->state = INST_RELEASE_RESOURCES;
388 
389 	return 0;
390 }
391 
392 int hfi_session_flush(struct venus_inst *inst)
393 {
394 	const struct hfi_ops *ops = inst->core->ops;
395 	int ret;
396 
397 	reinit_completion(&inst->done);
398 
399 	ret = ops->session_flush(inst, HFI_FLUSH_ALL);
400 	if (ret)
401 		return ret;
402 
403 	ret = wait_session_msg(inst);
404 	if (ret)
405 		return ret;
406 
407 	return 0;
408 }
409 EXPORT_SYMBOL_GPL(hfi_session_flush);
410 
411 int hfi_session_set_buffers(struct venus_inst *inst, struct hfi_buffer_desc *bd)
412 {
413 	const struct hfi_ops *ops = inst->core->ops;
414 
415 	return ops->session_set_buffers(inst, bd);
416 }
417 
418 int hfi_session_unset_buffers(struct venus_inst *inst,
419 			      struct hfi_buffer_desc *bd)
420 {
421 	const struct hfi_ops *ops = inst->core->ops;
422 	int ret;
423 
424 	reinit_completion(&inst->done);
425 
426 	ret = ops->session_unset_buffers(inst, bd);
427 	if (ret)
428 		return ret;
429 
430 	if (!bd->response_required)
431 		return 0;
432 
433 	ret = wait_session_msg(inst);
434 	if (ret)
435 		return ret;
436 
437 	return 0;
438 }
439 
440 int hfi_session_get_property(struct venus_inst *inst, u32 ptype,
441 			     union hfi_get_property *hprop)
442 {
443 	const struct hfi_ops *ops = inst->core->ops;
444 	int ret;
445 
446 	if (inst->state < INST_INIT || inst->state >= INST_STOP)
447 		return -EINVAL;
448 
449 	reinit_completion(&inst->done);
450 
451 	ret = ops->session_get_property(inst, ptype);
452 	if (ret)
453 		return ret;
454 
455 	ret = wait_session_msg(inst);
456 	if (ret)
457 		return ret;
458 
459 	*hprop = inst->hprop;
460 
461 	return 0;
462 }
463 EXPORT_SYMBOL_GPL(hfi_session_get_property);
464 
465 int hfi_session_set_property(struct venus_inst *inst, u32 ptype, void *pdata)
466 {
467 	const struct hfi_ops *ops = inst->core->ops;
468 
469 	if (inst->state < INST_INIT || inst->state >= INST_STOP)
470 		return -EINVAL;
471 
472 	return ops->session_set_property(inst, ptype, pdata);
473 }
474 EXPORT_SYMBOL_GPL(hfi_session_set_property);
475 
476 int hfi_session_process_buf(struct venus_inst *inst, struct hfi_frame_data *fd)
477 {
478 	const struct hfi_ops *ops = inst->core->ops;
479 
480 	if (fd->buffer_type == HFI_BUFFER_INPUT)
481 		return ops->session_etb(inst, fd);
482 	else if (fd->buffer_type == HFI_BUFFER_OUTPUT)
483 		return ops->session_ftb(inst, fd);
484 
485 	return -EINVAL;
486 }
487 
488 irqreturn_t hfi_isr_thread(int irq, void *dev_id)
489 {
490 	struct venus_core *core = dev_id;
491 
492 	return core->ops->isr_thread(core);
493 }
494 
495 irqreturn_t hfi_isr(int irq, void *dev)
496 {
497 	struct venus_core *core = dev;
498 
499 	return core->ops->isr(core);
500 }
501 
502 int hfi_create(struct venus_core *core, const struct hfi_core_ops *ops)
503 {
504 	int ret;
505 
506 	if (!ops)
507 		return -EINVAL;
508 
509 	atomic_set(&core->insts_count, 0);
510 	core->core_ops = ops;
511 	core->state = CORE_UNINIT;
512 	init_completion(&core->done);
513 	pkt_set_version(core->res->hfi_version);
514 	ret = venus_hfi_create(core);
515 
516 	return ret;
517 }
518 
519 void hfi_destroy(struct venus_core *core)
520 {
521 	venus_hfi_destroy(core);
522 }
523