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