blob: 5a8dd26ac7c607f94959824a9c5126ec803c0fe6 [file] [log] [blame]
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08001/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <asm/dma-iommu.h>
15#include <asm/memory.h>
16#include <linux/clk/qcom.h>
17#include <linux/coresight-stm.h>
18#include <linux/delay.h>
19#include <linux/devfreq.h>
20#include <linux/hash.h>
21#include <linux/interrupt.h>
22#include <linux/io.h>
23#include <linux/iommu.h>
24#include <linux/iopoll.h>
25#include <linux/of.h>
26#include <linux/pm_qos.h>
27#include <linux/regulator/consumer.h>
28#include <linux/slab.h>
29#include <linux/workqueue.h>
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -070030#include <linux/platform_device.h>
31#include <linux/soc/qcom/llcc-qcom.h>
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -080032#include <soc/qcom/scm.h>
33#include <soc/qcom/smem.h>
34#include <soc/qcom/subsystem_restart.h>
35#include "hfi_packetization.h"
36#include "msm_vidc_debug.h"
37#include "venus_hfi.h"
38#include "vidc_hfi_io.h"
39
40#define FIRMWARE_SIZE 0X00A00000
41#define REG_ADDR_OFFSET_BITMASK 0x000FFFFF
42#define QDSS_IOVA_START 0x80001000
43
44static struct hal_device_data hal_ctxt;
45
46#define TZBSP_MEM_PROTECT_VIDEO_VAR 0x8
47struct tzbsp_memprot {
48 u32 cp_start;
49 u32 cp_size;
50 u32 cp_nonpixel_start;
51 u32 cp_nonpixel_size;
52};
53
54struct tzbsp_resp {
55 int ret;
56};
57
58#define TZBSP_VIDEO_SET_STATE 0xa
59
60/* Poll interval in uS */
61#define POLL_INTERVAL_US 50
62
63enum tzbsp_video_state {
64 TZBSP_VIDEO_STATE_SUSPEND = 0,
65 TZBSP_VIDEO_STATE_RESUME = 1,
66 TZBSP_VIDEO_STATE_RESTORE_THRESHOLD = 2,
67};
68
69struct tzbsp_video_set_state_req {
70 u32 state; /* should be tzbsp_video_state enum value */
71 u32 spare; /* reserved for future, should be zero */
72};
73
74const struct msm_vidc_gov_data DEFAULT_BUS_VOTE = {
75 .data = NULL,
76 .data_count = 0,
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -080077};
78
79const int max_packets = 1000;
80
81static void venus_hfi_pm_handler(struct work_struct *work);
82static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_handler);
83static inline int __resume(struct venus_hfi_device *device);
84static inline int __suspend(struct venus_hfi_device *device);
85static int __disable_regulators(struct venus_hfi_device *device);
86static int __enable_regulators(struct venus_hfi_device *device);
87static inline int __prepare_enable_clks(struct venus_hfi_device *device);
88static inline void __disable_unprepare_clks(struct venus_hfi_device *device);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -080089static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet);
90static int __initialize_packetization(struct venus_hfi_device *device);
91static struct hal_session *__get_session(struct venus_hfi_device *device,
92 u32 session_id);
Praneeth Paladugub71968b2015-08-19 20:47:57 -070093static int __set_clocks(struct venus_hfi_device *device, u32 freq);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -080094static int __iface_cmdq_write(struct venus_hfi_device *device,
95 void *pkt);
96static int __load_fw(struct venus_hfi_device *device);
97static void __unload_fw(struct venus_hfi_device *device);
98static int __tzbsp_set_video_state(enum tzbsp_video_state state);
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -070099static int __enable_subcaches(struct venus_hfi_device *device);
100static int __disable_subcaches(struct venus_hfi_device *device);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -0800101
102
103/**
104 * Utility function to enforce some of our assumptions. Spam calls to this
105 * in hotspots in code to double check some of the assumptions that we hold.
106 */
107static inline void __strict_check(struct venus_hfi_device *device)
108{
109 WARN_ON(!mutex_is_locked(&device->lock));
110}
111
112static inline void __set_state(struct venus_hfi_device *device,
113 enum venus_hfi_state state)
114{
115 device->state = state;
116}
117
118static inline bool __core_in_valid_state(struct venus_hfi_device *device)
119{
120 return device->state != VENUS_STATE_DEINIT;
121}
122
123static void __dump_packet(u8 *packet, enum vidc_msg_prio log_level)
124{
125 u32 c = 0, packet_size = *(u32 *)packet;
126 const int row_size = 32;
127 /*
128 * row must contain enough for 0xdeadbaad * 8 to be converted into
129 * "de ad ba ab " * 8 + '\0'
130 */
131 char row[3 * row_size];
132
133 for (c = 0; c * row_size < packet_size; ++c) {
134 int bytes_to_read = ((c + 1) * row_size > packet_size) ?
135 packet_size % row_size : row_size;
136 hex_dump_to_buffer(packet + c * row_size, bytes_to_read,
137 row_size, 4, row, sizeof(row), false);
138 dprintk(log_level, "%s\n", row);
139 }
140}
141
142static void __sim_modify_cmd_packet(u8 *packet, struct venus_hfi_device *device)
143{
144 struct hfi_cmd_sys_session_init_packet *sys_init;
145 struct hal_session *session = NULL;
146 u8 i;
147 phys_addr_t fw_bias = 0;
148
149 if (!device || !packet) {
150 dprintk(VIDC_ERR, "Invalid Param\n");
151 return;
152 } else if (!device->hal_data->firmware_base
153 || is_iommu_present(device->res)) {
154 return;
155 }
156
157 fw_bias = device->hal_data->firmware_base;
158 sys_init = (struct hfi_cmd_sys_session_init_packet *)packet;
159
160 session = __get_session(device, sys_init->session_id);
161 if (!session) {
162 dprintk(VIDC_DBG, "%s :Invalid session id: %x\n",
163 __func__, sys_init->session_id);
164 return;
165 }
166
167 switch (sys_init->packet_type) {
168 case HFI_CMD_SESSION_EMPTY_BUFFER:
169 if (session->is_decoder) {
170 struct hfi_cmd_session_empty_buffer_compressed_packet
171 *pkt = (struct
172 hfi_cmd_session_empty_buffer_compressed_packet
173 *) packet;
174 pkt->packet_buffer -= fw_bias;
175 } else {
176 struct
177 hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
178 *pkt = (struct
179 hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
180 *) packet;
181 pkt->packet_buffer -= fw_bias;
182 }
183 break;
184 case HFI_CMD_SESSION_FILL_BUFFER:
185 {
186 struct hfi_cmd_session_fill_buffer_packet *pkt =
187 (struct hfi_cmd_session_fill_buffer_packet *)packet;
188 pkt->packet_buffer -= fw_bias;
189 break;
190 }
191 case HFI_CMD_SESSION_SET_BUFFERS:
192 {
193 struct hfi_cmd_session_set_buffers_packet *pkt =
194 (struct hfi_cmd_session_set_buffers_packet *)packet;
195 if (pkt->buffer_type == HFI_BUFFER_OUTPUT ||
196 pkt->buffer_type == HFI_BUFFER_OUTPUT2) {
197 struct hfi_buffer_info *buff;
198
199 buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
200 buff->buffer_addr -= fw_bias;
201 if (buff->extra_data_addr >= fw_bias)
202 buff->extra_data_addr -= fw_bias;
203 } else {
204 for (i = 0; i < pkt->num_buffers; i++)
205 pkt->rg_buffer_info[i] -= fw_bias;
206 }
207 break;
208 }
209 case HFI_CMD_SESSION_RELEASE_BUFFERS:
210 {
211 struct hfi_cmd_session_release_buffer_packet *pkt =
212 (struct hfi_cmd_session_release_buffer_packet *)packet;
213
214 if (pkt->buffer_type == HFI_BUFFER_OUTPUT ||
215 pkt->buffer_type == HFI_BUFFER_OUTPUT2) {
216 struct hfi_buffer_info *buff;
217
218 buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
219 buff->buffer_addr -= fw_bias;
220 buff->extra_data_addr -= fw_bias;
221 } else {
222 for (i = 0; i < pkt->num_buffers; i++)
223 pkt->rg_buffer_info[i] -= fw_bias;
224 }
225 break;
226 }
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -0800227 default:
228 break;
229 }
230}
231
232static int __acquire_regulator(struct regulator_info *rinfo)
233{
234 int rc = 0;
235
236 if (rinfo->has_hw_power_collapse) {
237 rc = regulator_set_mode(rinfo->regulator,
238 REGULATOR_MODE_NORMAL);
239 if (rc) {
240 /*
241 * This is somewhat fatal, but nothing we can do
242 * about it. We can't disable the regulator w/o
243 * getting it back under s/w control
244 */
245 dprintk(VIDC_WARN,
246 "Failed to acquire regulator control: %s\n",
247 rinfo->name);
248 } else {
249
250 dprintk(VIDC_DBG,
251 "Acquire regulator control from HW: %s\n",
252 rinfo->name);
253
254 }
255 }
256
257 if (!regulator_is_enabled(rinfo->regulator)) {
258 dprintk(VIDC_WARN, "Regulator is not enabled %s\n",
259 rinfo->name);
260 WARN_ON(1);
261 }
262
263 return rc;
264}
265
266static int __hand_off_regulator(struct regulator_info *rinfo)
267{
268 int rc = 0;
269
270 if (rinfo->has_hw_power_collapse) {
271 rc = regulator_set_mode(rinfo->regulator,
272 REGULATOR_MODE_FAST);
273 if (rc) {
274 dprintk(VIDC_WARN,
275 "Failed to hand off regulator control: %s\n",
276 rinfo->name);
277 } else {
278 dprintk(VIDC_DBG,
279 "Hand off regulator control to HW: %s\n",
280 rinfo->name);
281 }
282 }
283
284 return rc;
285}
286
287static int __hand_off_regulators(struct venus_hfi_device *device)
288{
289 struct regulator_info *rinfo;
290 int rc = 0, c = 0;
291
292 venus_hfi_for_each_regulator(device, rinfo) {
293 rc = __hand_off_regulator(rinfo);
294 /*
295 * If one regulator hand off failed, driver should take
296 * the control for other regulators back.
297 */
298 if (rc)
299 goto err_reg_handoff_failed;
300 c++;
301 }
302
303 return rc;
304err_reg_handoff_failed:
305 venus_hfi_for_each_regulator_reverse_continue(device, rinfo, c)
306 __acquire_regulator(rinfo);
307
308 return rc;
309}
310
311static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
312 bool *rx_req_is_set)
313{
314 struct hfi_queue_header *queue;
315 u32 packet_size_in_words, new_write_idx;
316 u32 empty_space, read_idx;
317 u32 *write_ptr;
318
319 if (!qinfo || !packet) {
320 dprintk(VIDC_ERR, "Invalid Params\n");
321 return -EINVAL;
322 } else if (!qinfo->q_array.align_virtual_addr) {
323 dprintk(VIDC_WARN, "Queues have already been freed\n");
324 return -EINVAL;
325 }
326
327 queue = (struct hfi_queue_header *) qinfo->q_hdr;
328 if (!queue) {
329 dprintk(VIDC_ERR, "queue not present\n");
330 return -ENOENT;
331 }
332
333 if (msm_vidc_debug & VIDC_PKT) {
334 dprintk(VIDC_PKT, "%s: %pK\n", __func__, qinfo);
335 __dump_packet(packet, VIDC_PKT);
336 }
337
338 packet_size_in_words = (*(u32 *)packet) >> 2;
339 if (!packet_size_in_words) {
340 dprintk(VIDC_ERR, "Zero packet size\n");
341 return -ENODATA;
342 }
343
344 read_idx = queue->qhdr_read_idx;
345
346 empty_space = (queue->qhdr_write_idx >= read_idx) ?
347 (queue->qhdr_q_size - (queue->qhdr_write_idx - read_idx)) :
348 (read_idx - queue->qhdr_write_idx);
349 if (empty_space <= packet_size_in_words) {
350 queue->qhdr_tx_req = 1;
351 dprintk(VIDC_ERR, "Insufficient size (%d) to write (%d)\n",
352 empty_space, packet_size_in_words);
353 return -ENOTEMPTY;
354 }
355
356 queue->qhdr_tx_req = 0;
357
358 new_write_idx = (queue->qhdr_write_idx + packet_size_in_words);
359 write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
360 (queue->qhdr_write_idx << 2));
361 if (new_write_idx < queue->qhdr_q_size) {
362 memcpy(write_ptr, packet, packet_size_in_words << 2);
363 } else {
364 new_write_idx -= queue->qhdr_q_size;
365 memcpy(write_ptr, packet, (packet_size_in_words -
366 new_write_idx) << 2);
367 memcpy((void *)qinfo->q_array.align_virtual_addr,
368 packet + ((packet_size_in_words - new_write_idx) << 2),
369 new_write_idx << 2);
370 }
371
372 /*
373 * Memory barrier to make sure packet is written before updating the
374 * write index
375 */
376 mb();
377 queue->qhdr_write_idx = new_write_idx;
378 if (rx_req_is_set)
379 *rx_req_is_set = queue->qhdr_rx_req == 1;
380 /*
381 * Memory barrier to make sure write index is updated before an
382 * interrupt is raised on venus.
383 */
384 mb();
385 return 0;
386}
387
388static void __hal_sim_modify_msg_packet(u8 *packet,
389 struct venus_hfi_device *device)
390{
391 struct hfi_msg_sys_session_init_done_packet *sys_idle;
392 struct hal_session *session = NULL;
393 phys_addr_t fw_bias = 0;
394
395 if (!device || !packet) {
396 dprintk(VIDC_ERR, "Invalid Param\n");
397 return;
398 } else if (!device->hal_data->firmware_base
399 || is_iommu_present(device->res)) {
400 return;
401 }
402
403 fw_bias = device->hal_data->firmware_base;
404 sys_idle = (struct hfi_msg_sys_session_init_done_packet *)packet;
405 session = __get_session(device, sys_idle->session_id);
406
407 if (!session) {
408 dprintk(VIDC_DBG, "%s: Invalid session id: %x\n",
409 __func__, sys_idle->session_id);
410 return;
411 }
412
413 switch (sys_idle->packet_type) {
414 case HFI_MSG_SESSION_FILL_BUFFER_DONE:
415 if (session->is_decoder) {
416 struct
417 hfi_msg_session_fbd_uncompressed_plane0_packet
418 *pkt_uc = (struct
419 hfi_msg_session_fbd_uncompressed_plane0_packet
420 *) packet;
421 pkt_uc->packet_buffer += fw_bias;
422 } else {
423 struct
424 hfi_msg_session_fill_buffer_done_compressed_packet
425 *pkt = (struct
426 hfi_msg_session_fill_buffer_done_compressed_packet
427 *) packet;
428 pkt->packet_buffer += fw_bias;
429 }
430 break;
431 case HFI_MSG_SESSION_EMPTY_BUFFER_DONE:
432 {
433 struct hfi_msg_session_empty_buffer_done_packet *pkt =
434 (struct hfi_msg_session_empty_buffer_done_packet *)packet;
435 pkt->packet_buffer += fw_bias;
436 break;
437 }
438 case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE:
439 {
440 struct
441 hfi_msg_session_get_sequence_header_done_packet
442 *pkt =
443 (struct hfi_msg_session_get_sequence_header_done_packet *)
444 packet;
445 pkt->sequence_header += fw_bias;
446 break;
447 }
448 default:
449 break;
450 }
451}
452
453static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet,
454 u32 *pb_tx_req_is_set)
455{
456 struct hfi_queue_header *queue;
457 u32 packet_size_in_words, new_read_idx;
458 u32 *read_ptr;
459 u32 receive_request = 0;
460 int rc = 0;
461
462 if (!qinfo || !packet || !pb_tx_req_is_set) {
463 dprintk(VIDC_ERR, "Invalid Params\n");
464 return -EINVAL;
465 } else if (!qinfo->q_array.align_virtual_addr) {
466 dprintk(VIDC_WARN, "Queues have already been freed\n");
467 return -EINVAL;
468 }
469
470 /*
471 * Memory barrier to make sure data is valid before
472 *reading it
473 */
474 mb();
475 queue = (struct hfi_queue_header *) qinfo->q_hdr;
476
477 if (!queue) {
478 dprintk(VIDC_ERR, "Queue memory is not allocated\n");
479 return -ENOMEM;
480 }
481
482 /*
483 * Do not set receive request for debug queue, if set,
484 * Venus generates interrupt for debug messages even
485 * when there is no response message available.
486 * In general debug queue will not become full as it
487 * is being emptied out for every interrupt from Venus.
488 * Venus will anyway generates interrupt if it is full.
489 */
490 if (queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_MSG_Q)
491 receive_request = 1;
492
493 if (queue->qhdr_read_idx == queue->qhdr_write_idx) {
494 queue->qhdr_rx_req = receive_request;
495 *pb_tx_req_is_set = 0;
496 dprintk(VIDC_DBG,
497 "%s queue is empty, rx_req = %u, tx_req = %u, read_idx = %u\n",
498 receive_request ? "message" : "debug",
499 queue->qhdr_rx_req, queue->qhdr_tx_req,
500 queue->qhdr_read_idx);
501 return -ENODATA;
502 }
503
504 read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
505 (queue->qhdr_read_idx << 2));
506 packet_size_in_words = (*read_ptr) >> 2;
507 if (!packet_size_in_words) {
508 dprintk(VIDC_ERR, "Zero packet size\n");
509 return -ENODATA;
510 }
511
512 new_read_idx = queue->qhdr_read_idx + packet_size_in_words;
513 if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE)
514 && queue->qhdr_read_idx <= queue->qhdr_q_size) {
515 if (new_read_idx < queue->qhdr_q_size) {
516 memcpy(packet, read_ptr,
517 packet_size_in_words << 2);
518 } else {
519 new_read_idx -= queue->qhdr_q_size;
520 memcpy(packet, read_ptr,
521 (packet_size_in_words - new_read_idx) << 2);
522 memcpy(packet + ((packet_size_in_words -
523 new_read_idx) << 2),
524 (u8 *)qinfo->q_array.align_virtual_addr,
525 new_read_idx << 2);
526 }
527 } else {
528 dprintk(VIDC_WARN,
529 "BAD packet received, read_idx: %#x, pkt_size: %d\n",
530 queue->qhdr_read_idx, packet_size_in_words << 2);
531 dprintk(VIDC_WARN, "Dropping this packet\n");
532 new_read_idx = queue->qhdr_write_idx;
533 rc = -ENODATA;
534 }
535
536 queue->qhdr_read_idx = new_read_idx;
537
538 if (queue->qhdr_read_idx != queue->qhdr_write_idx)
539 queue->qhdr_rx_req = 0;
540 else
541 queue->qhdr_rx_req = receive_request;
542
543 *pb_tx_req_is_set = (queue->qhdr_tx_req == 1) ? 1 : 0;
544
Maheshwar Ajja6a990572017-03-31 15:31:57 -0700545 if ((msm_vidc_debug & VIDC_PKT) &&
546 !(queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q)) {
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -0800547 dprintk(VIDC_PKT, "%s: %pK\n", __func__, qinfo);
548 __dump_packet(packet, VIDC_PKT);
549 }
550
551 return rc;
552}
553
554static int __smem_alloc(struct venus_hfi_device *dev,
555 struct vidc_mem_addr *mem, u32 size, u32 align,
556 u32 flags, u32 usage)
557{
558 struct msm_smem *alloc = NULL;
559 int rc = 0;
560
561 if (!dev || !dev->hal_client || !mem || !size) {
562 dprintk(VIDC_ERR, "Invalid Params\n");
563 return -EINVAL;
564 }
565
566 dprintk(VIDC_INFO, "start to alloc size: %d, flags: %d\n", size, flags);
567 alloc = msm_smem_alloc(dev->hal_client, size, align, flags, usage, 1);
568 if (!alloc) {
569 dprintk(VIDC_ERR, "Alloc failed\n");
570 rc = -ENOMEM;
571 goto fail_smem_alloc;
572 }
573
574 dprintk(VIDC_DBG, "__smem_alloc: ptr = %pK, size = %d\n",
575 alloc->kvaddr, size);
576 rc = msm_smem_cache_operations(dev->hal_client, alloc,
577 SMEM_CACHE_CLEAN);
578 if (rc) {
579 dprintk(VIDC_WARN, "Failed to clean cache\n");
580 dprintk(VIDC_WARN, "This may result in undefined behavior\n");
581 }
582
583 mem->mem_size = alloc->size;
584 mem->mem_data = alloc;
585 mem->align_virtual_addr = alloc->kvaddr;
586 mem->align_device_addr = alloc->device_addr;
587 return rc;
588fail_smem_alloc:
589 return rc;
590}
591
592static void __smem_free(struct venus_hfi_device *dev, struct msm_smem *mem)
593{
594 if (!dev || !mem) {
595 dprintk(VIDC_ERR, "invalid param %pK %pK\n", dev, mem);
596 return;
597 }
598
599 msm_smem_free(dev->hal_client, mem);
600}
601
602static void __write_register(struct venus_hfi_device *device,
603 u32 reg, u32 value)
604{
605 u32 hwiosymaddr = reg;
606 u8 *base_addr;
607
608 if (!device) {
609 dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
610 return;
611 }
612
613 __strict_check(device);
614
615 if (!device->power_enabled) {
616 dprintk(VIDC_WARN,
617 "HFI Write register failed : Power is OFF\n");
618 WARN_ON(1);
619 return;
620 }
621
622 base_addr = device->hal_data->register_base;
623 dprintk(VIDC_DBG, "Base addr: %pK, written to: %#x, Value: %#x...\n",
624 base_addr, hwiosymaddr, value);
625 base_addr += hwiosymaddr;
626 writel_relaxed(value, base_addr);
627
628 /*
629 * Memory barrier to make sure value is written into the register.
630 */
631 wmb();
632}
633
634static int __read_register(struct venus_hfi_device *device, u32 reg)
635{
636 int rc = 0;
637 u8 *base_addr;
638
639 if (!device) {
640 dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
641 return -EINVAL;
642 }
643
644 __strict_check(device);
645
646 if (!device->power_enabled) {
647 dprintk(VIDC_WARN,
648 "HFI Read register failed : Power is OFF\n");
649 WARN_ON(1);
650 return -EINVAL;
651 }
652
653 base_addr = device->hal_data->register_base;
654
655 rc = readl_relaxed(base_addr + reg);
656 /*
657 * Memory barrier to make sure value is read correctly from the
658 * register.
659 */
660 rmb();
661 dprintk(VIDC_DBG, "Base addr: %pK, read from: %#x, value: %#x...\n",
662 base_addr, reg, rc);
663
664 return rc;
665}
666
667static void __set_registers(struct venus_hfi_device *device)
668{
669 struct reg_set *reg_set;
670 int i;
671
672 if (!device->res) {
673 dprintk(VIDC_ERR,
674 "device resources null, cannot set registers\n");
675 return;
676 }
677
678 reg_set = &device->res->reg_set;
679 for (i = 0; i < reg_set->count; i++) {
680 __write_register(device, reg_set->reg_tbl[i].reg,
681 reg_set->reg_tbl[i].value);
682 }
683}
684
685/*
686 * The existence of this function is a hack for 8996 (or certain Venus versions)
687 * to overcome a hardware bug. Whenever the GDSCs momentarily power collapse
688 * (after calling __hand_off_regulators()), the values of the threshold
689 * registers (typically programmed by TZ) are incorrectly reset. As a result
690 * reprogram these registers at certain agreed upon points.
691 */
692static void __set_threshold_registers(struct venus_hfi_device *device)
693{
694 u32 version = __read_register(device, VIDC_WRAPPER_HW_VERSION);
695
696 version &= ~GENMASK(15, 0);
697 if (version != (0x3 << 28 | 0x43 << 16))
698 return;
699
700 if (__tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESTORE_THRESHOLD))
701 dprintk(VIDC_ERR, "Failed to restore threshold values\n");
702}
703
704static void __iommu_detach(struct venus_hfi_device *device)
705{
706 struct context_bank_info *cb;
707
708 if (!device || !device->res) {
709 dprintk(VIDC_ERR, "Invalid parameter: %pK\n", device);
710 return;
711 }
712
713 list_for_each_entry(cb, &device->res->context_banks, list) {
714 if (cb->dev)
715 arm_iommu_detach_device(cb->dev);
716 if (cb->mapping)
717 arm_iommu_release_mapping(cb->mapping);
718 }
719}
720
721static bool __is_session_supported(unsigned long sessions_supported,
722 enum vidc_vote_data_session session_type)
723{
724 bool same_codec, same_session_type;
725 int codec_bit, session_type_bit;
726 unsigned long session = session_type;
727
728 if (!sessions_supported || !session)
729 return false;
730
731 /* ffs returns a 1 indexed, test_bit takes a 0 indexed...index */
732 codec_bit = ffs(session) - 1;
733 session_type_bit = codec_bit + 1;
734
735 same_codec = test_bit(codec_bit, &sessions_supported) ==
736 test_bit(codec_bit, &session);
737 same_session_type = test_bit(session_type_bit, &sessions_supported) ==
738 test_bit(session_type_bit, &session);
739
740 return same_codec && same_session_type;
741}
742
743bool venus_hfi_is_session_supported(unsigned long sessions_supported,
744 enum vidc_vote_data_session session_type)
745{
746 return __is_session_supported(sessions_supported, session_type);
747}
748EXPORT_SYMBOL(venus_hfi_is_session_supported);
749
750static int __devfreq_target(struct device *devfreq_dev,
751 unsigned long *freq, u32 flags)
752{
753 int rc = 0;
754 uint64_t ab = 0;
755 struct bus_info *bus = NULL, *temp = NULL;
756 struct venus_hfi_device *device = dev_get_drvdata(devfreq_dev);
757
758 venus_hfi_for_each_bus(device, temp) {
759 if (temp->dev == devfreq_dev) {
760 bus = temp;
761 break;
762 }
763 }
764
765 if (!bus) {
766 rc = -EBADHANDLE;
767 goto err_unknown_device;
768 }
769
770 /*
771 * Clamp for all non zero frequencies. This clamp is necessary to stop
772 * devfreq driver from spamming - Couldn't update frequency - logs, if
773 * the scaled ab value is not part of the frequency table.
774 */
775 if (*freq)
776 *freq = clamp_t(typeof(*freq), *freq, bus->range[0],
777 bus->range[1]);
778
779 /* we expect governors to provide values in kBps form, convert to Bps */
780 ab = *freq * 1000;
781 rc = msm_bus_scale_update_bw(bus->client, ab, 0);
782 if (rc) {
783 dprintk(VIDC_ERR, "Failed voting bus %s to ab %llu\n: %d",
784 bus->name, ab, rc);
785 goto err_unknown_device;
786 }
787
788 dprintk(VIDC_PROF, "Voting bus %s to ab %llu\n", bus->name, ab);
789
790 return 0;
791err_unknown_device:
792 return rc;
793}
794
795static int __devfreq_get_status(struct device *devfreq_dev,
796 struct devfreq_dev_status *stat)
797{
798 int rc = 0;
799 struct bus_info *bus = NULL, *temp = NULL;
800 struct venus_hfi_device *device = dev_get_drvdata(devfreq_dev);
801
802 venus_hfi_for_each_bus(device, temp) {
803 if (temp->dev == devfreq_dev) {
804 bus = temp;
805 break;
806 }
807 }
808
809 if (!bus) {
810 rc = -EBADHANDLE;
811 goto err_unknown_device;
812 }
813
814 *stat = (struct devfreq_dev_status) {
815 .private_data = &device->bus_vote,
816 /*
817 * Put in dummy place holder values for upstream govs, our
818 * custom gov only needs .private_data. We should fill this in
819 * properly if we can actually measure busy_time accurately
820 * (which we can't at the moment)
821 */
822 .total_time = 1,
823 .busy_time = 1,
824 .current_frequency = 0,
825 };
826
827err_unknown_device:
828 return rc;
829}
830
831static int __unvote_buses(struct venus_hfi_device *device)
832{
833 int rc = 0;
834 struct bus_info *bus = NULL;
835
836 venus_hfi_for_each_bus(device, bus) {
837 int local_rc = 0;
838 unsigned long zero = 0;
839
840 rc = devfreq_suspend_device(bus->devfreq);
841 if (rc)
842 goto err_unknown_device;
843
844 local_rc = __devfreq_target(bus->dev, &zero, 0);
845 rc = rc ?: local_rc;
846 }
847
848 if (rc)
849 dprintk(VIDC_WARN, "Failed to unvote some buses\n");
850
851err_unknown_device:
852 return rc;
853}
854
855static int __vote_buses(struct venus_hfi_device *device,
856 struct vidc_bus_vote_data *data, int num_data)
857{
858 int rc = 0;
859 struct bus_info *bus = NULL;
860 struct vidc_bus_vote_data *new_data = NULL;
861
862 if (!num_data) {
863 dprintk(VIDC_DBG, "No vote data available\n");
864 goto no_data_count;
865 } else if (!data) {
866 dprintk(VIDC_ERR, "Invalid voting data\n");
867 return -EINVAL;
868 }
869
870 new_data = kmemdup(data, num_data * sizeof(*new_data), GFP_KERNEL);
871 if (!new_data) {
872 dprintk(VIDC_ERR, "Can't alloc memory to cache bus votes\n");
873 rc = -ENOMEM;
874 goto err_no_mem;
875 }
876
877no_data_count:
878 kfree(device->bus_vote.data);
879 device->bus_vote.data = new_data;
880 device->bus_vote.data_count = num_data;
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -0800881
882 venus_hfi_for_each_bus(device, bus) {
883 if (bus && bus->devfreq) {
884 /* NOP if already resume */
885 rc = devfreq_resume_device(bus->devfreq);
886 if (rc)
887 goto err_no_mem;
888
889 /* Kick devfreq awake incase _resume() didn't do it */
Praneeth Paladuguf3a8e5f2016-12-14 11:04:17 -0800890
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -0800891 bus->devfreq->nb.notifier_call(
892 &bus->devfreq->nb, 0, NULL);
893 }
894 }
895
896err_no_mem:
897 return rc;
898}
899
900static int venus_hfi_vote_buses(void *dev, struct vidc_bus_vote_data *d, int n)
901{
902 int rc = 0;
903 struct venus_hfi_device *device = dev;
904
905 if (!device)
906 return -EINVAL;
907
908 mutex_lock(&device->lock);
909 rc = __vote_buses(device, d, n);
910 mutex_unlock(&device->lock);
911
912 return rc;
913
914}
915static int __core_set_resource(struct venus_hfi_device *device,
916 struct vidc_resource_hdr *resource_hdr, void *resource_value)
917{
918 struct hfi_cmd_sys_set_resource_packet *pkt;
919 u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
920 int rc = 0;
921
922 if (!device || !resource_hdr || !resource_value) {
923 dprintk(VIDC_ERR, "set_res: Invalid Params\n");
924 return -EINVAL;
925 }
926
927 pkt = (struct hfi_cmd_sys_set_resource_packet *) packet;
928
929 rc = call_hfi_pkt_op(device, sys_set_resource,
930 pkt, resource_hdr, resource_value);
931 if (rc) {
932 dprintk(VIDC_ERR, "set_res: failed to create packet\n");
933 goto err_create_pkt;
934 }
935
936 rc = __iface_cmdq_write(device, pkt);
937 if (rc)
938 rc = -ENOTEMPTY;
939
940err_create_pkt:
941 return rc;
942}
943
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -0700944static int __core_release_resource(struct venus_hfi_device *device,
945 struct vidc_resource_hdr *resource_hdr)
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -0800946{
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -0700947 struct hfi_cmd_sys_release_resource_packet *pkt;
948 u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -0800949 int rc = 0;
950
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -0700951 if (!device || !resource_hdr) {
952 dprintk(VIDC_ERR, "release_res: Invalid Params\n");
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -0800953 return -EINVAL;
954 }
955
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -0700956 pkt = (struct hfi_cmd_sys_release_resource_packet *) packet;
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -0800957
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -0700958 rc = call_hfi_pkt_op(device, sys_release_resource,
959 pkt, resource_hdr);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -0800960
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -0800961 if (rc) {
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -0700962 dprintk(VIDC_ERR, "release_res: failed to create packet\n");
963 goto err_create_pkt;
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -0800964 }
965
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -0700966 rc = __iface_cmdq_write(device, pkt);
967 if (rc)
968 rc = -ENOTEMPTY;
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -0800969
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -0700970err_create_pkt:
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -0800971 return rc;
972}
973
974static int __tzbsp_set_video_state(enum tzbsp_video_state state)
975{
976 struct tzbsp_video_set_state_req cmd = {0};
977 int tzbsp_rsp = 0;
978 int rc = 0;
979 struct scm_desc desc = {0};
980
981 desc.args[0] = cmd.state = state;
982 desc.args[1] = cmd.spare = 0;
983 desc.arginfo = SCM_ARGS(2);
984
985 if (!is_scm_armv8()) {
986 rc = scm_call(SCM_SVC_BOOT, TZBSP_VIDEO_SET_STATE, &cmd,
987 sizeof(cmd), &tzbsp_rsp, sizeof(tzbsp_rsp));
988 } else {
989 rc = scm_call2(SCM_SIP_FNID(SCM_SVC_BOOT,
990 TZBSP_VIDEO_SET_STATE), &desc);
991 tzbsp_rsp = desc.ret[0];
992 }
993
994 if (rc) {
995 dprintk(VIDC_ERR, "Failed scm_call %d\n", rc);
996 return rc;
997 }
998
999 dprintk(VIDC_DBG, "Set state %d, resp %d\n", state, tzbsp_rsp);
1000 if (tzbsp_rsp) {
1001 dprintk(VIDC_ERR,
1002 "Failed to set video core state to suspend: %d\n",
1003 tzbsp_rsp);
1004 return -EINVAL;
1005 }
1006
1007 return 0;
1008}
1009
1010static inline int __boot_firmware(struct venus_hfi_device *device)
1011{
1012 int rc = 0;
Praneeth Paladuguf3a8e5f2016-12-14 11:04:17 -08001013 u32 ctrl_status = 0, count = 0, max_tries = 1000;
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08001014
1015 __write_register(device, VIDC_CTRL_INIT, 0x1);
1016 while (!ctrl_status && count < max_tries) {
1017 ctrl_status = __read_register(device, VIDC_CPU_CS_SCIACMDARG0);
1018 if ((ctrl_status & 0xFE) == 0x4) {
1019 dprintk(VIDC_ERR, "invalid setting for UC_REGION\n");
1020 break;
1021 }
1022
Praneeth Paladuguf3a8e5f2016-12-14 11:04:17 -08001023 usleep_range(50, 100);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08001024 count++;
1025 }
1026
1027 if (count >= max_tries) {
1028 dprintk(VIDC_ERR, "Error booting up vidc firmware\n");
1029 rc = -ETIME;
1030 }
1031 return rc;
1032}
1033
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08001034static int venus_hfi_suspend(void *dev)
1035{
1036 int rc = 0;
1037 struct venus_hfi_device *device = (struct venus_hfi_device *) dev;
1038
1039 if (!device) {
1040 dprintk(VIDC_ERR, "%s invalid device\n", __func__);
1041 return -EINVAL;
1042 } else if (!device->res->sw_power_collapsible) {
1043 return -ENOTSUPP;
1044 }
1045
1046 dprintk(VIDC_DBG, "Suspending Venus\n");
1047 rc = flush_delayed_work(&venus_hfi_pm_work);
1048
1049 return rc;
1050}
1051
1052static int venus_hfi_flush_debug_queue(void *dev)
1053{
1054 int rc = 0;
1055 struct venus_hfi_device *device = (struct venus_hfi_device *) dev;
1056
1057 if (!device) {
1058 dprintk(VIDC_ERR, "%s invalid device\n", __func__);
1059 return -EINVAL;
1060 }
1061
1062 mutex_lock(&device->lock);
1063
1064 if (device->power_enabled) {
1065 dprintk(VIDC_DBG, "Venus is busy\n");
1066 rc = -EBUSY;
1067 goto exit;
1068 }
1069 __flush_debug_queue(device, NULL);
1070exit:
1071 mutex_unlock(&device->lock);
1072 return rc;
1073}
1074
1075static enum hal_default_properties venus_hfi_get_default_properties(void *dev)
1076{
1077 enum hal_default_properties prop = 0;
1078 struct venus_hfi_device *device = (struct venus_hfi_device *) dev;
1079
1080 if (!device) {
1081 dprintk(VIDC_ERR, "%s invalid device\n", __func__);
1082 return -EINVAL;
1083 }
1084
1085 mutex_lock(&device->lock);
1086
Chinmay Sawarkar2de3f772017-02-07 12:03:44 -08001087 prop = HAL_VIDEO_DYNAMIC_BUF_MODE;
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08001088
1089 mutex_unlock(&device->lock);
1090 return prop;
1091}
1092
Praneeth Paladugub71968b2015-08-19 20:47:57 -07001093static int __set_clocks(struct venus_hfi_device *device, u32 freq)
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08001094{
1095 struct clock_info *cl;
Praneeth Paladugub71968b2015-08-19 20:47:57 -07001096 int rc = 0;
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08001097
1098 venus_hfi_for_each_clock(device, cl) {
Praneeth Paladugub71968b2015-08-19 20:47:57 -07001099 if (cl->has_scaling) {/* has_scaling */
1100 device->clk_freq = freq;
1101 rc = clk_set_rate(cl->clk, freq);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08001102 if (rc) {
1103 dprintk(VIDC_ERR,
Praneeth Paladugub71968b2015-08-19 20:47:57 -07001104 "Failed to set clock rate %u %s: %d %s\n",
1105 freq, cl->name, rc, __func__);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08001106 return rc;
1107 }
1108
Praneeth Paladugub71968b2015-08-19 20:47:57 -07001109 dprintk(VIDC_PROF, "Scaling clock %s to %u\n",
1110 cl->name, freq);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08001111 }
1112 }
1113
1114 return 0;
1115}
1116
Praneeth Paladugub71968b2015-08-19 20:47:57 -07001117static int venus_hfi_scale_clocks(void *dev, u32 freq)
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08001118{
1119 int rc = 0;
1120 struct venus_hfi_device *device = dev;
1121
1122 if (!device) {
1123 dprintk(VIDC_ERR, "Invalid args: %pK\n", device);
1124 return -EINVAL;
1125 }
1126
1127 mutex_lock(&device->lock);
1128
1129 if (__resume(device)) {
1130 dprintk(VIDC_ERR, "Resume from power collapse failed\n");
1131 rc = -ENODEV;
1132 goto exit;
1133 }
1134
Praneeth Paladugub71968b2015-08-19 20:47:57 -07001135 rc = __set_clocks(device, freq);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08001136exit:
1137 mutex_unlock(&device->lock);
Praneeth Paladugub71968b2015-08-19 20:47:57 -07001138
1139 return rc;
1140}
1141
1142static int __scale_clocks(struct venus_hfi_device *device)
1143{
1144 int rc = 0;
1145 struct clock_freq_table *clk_freq_tbl = NULL;
1146 struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
1147 u32 rate = 0;
1148
1149 clk_freq_tbl = &device->res->clock_freq_tbl;
1150 allowed_clks_tbl = device->res->allowed_clks_tbl;
1151
1152 dprintk(VIDC_DBG, "%s: NULL scale data\n", __func__);
1153 rate = device->clk_freq ? device->clk_freq :
1154 allowed_clks_tbl[0].clock_rate;
1155
1156 rc = __set_clocks(device, rate);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08001157 return rc;
1158}
1159
1160/* Writes into cmdq without raising an interrupt */
1161static int __iface_cmdq_write_relaxed(struct venus_hfi_device *device,
1162 void *pkt, bool *requires_interrupt)
1163{
1164 struct vidc_iface_q_info *q_info;
1165 struct vidc_hal_cmd_pkt_hdr *cmd_packet;
1166 int result = -E2BIG;
1167
1168 if (!device || !pkt) {
1169 dprintk(VIDC_ERR, "Invalid Params\n");
1170 return -EINVAL;
1171 }
1172
1173 __strict_check(device);
1174
1175 if (!__core_in_valid_state(device)) {
1176 dprintk(VIDC_DBG, "%s - fw not in init state\n", __func__);
1177 result = -EINVAL;
1178 goto err_q_null;
1179 }
1180
1181 cmd_packet = (struct vidc_hal_cmd_pkt_hdr *)pkt;
1182 device->last_packet_type = cmd_packet->packet_type;
1183
1184 q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
1185 if (!q_info) {
1186 dprintk(VIDC_ERR, "cannot write to shared Q's\n");
1187 goto err_q_null;
1188 }
1189
1190 if (!q_info->q_array.align_virtual_addr) {
1191 dprintk(VIDC_ERR, "cannot write to shared CMD Q's\n");
1192 result = -ENODATA;
1193 goto err_q_null;
1194 }
1195
1196 __sim_modify_cmd_packet((u8 *)pkt, device);
1197 if (__resume(device)) {
1198 dprintk(VIDC_ERR, "%s: Power on failed\n", __func__);
1199 goto err_q_write;
1200 }
1201
1202 if (!__write_queue(q_info, (u8 *)pkt, requires_interrupt)) {
1203 if (device->res->sw_power_collapsible) {
1204 cancel_delayed_work(&venus_hfi_pm_work);
1205 if (!queue_delayed_work(device->venus_pm_workq,
1206 &venus_hfi_pm_work,
1207 msecs_to_jiffies(
1208 msm_vidc_pwr_collapse_delay))) {
1209 dprintk(VIDC_DBG,
1210 "PM work already scheduled\n");
1211 }
1212 }
1213
1214 result = 0;
1215 } else {
1216 dprintk(VIDC_ERR, "__iface_cmdq_write: queue full\n");
1217 }
1218
1219err_q_write:
1220err_q_null:
1221 return result;
1222}
1223
1224static int __iface_cmdq_write(struct venus_hfi_device *device, void *pkt)
1225{
1226 bool needs_interrupt = false;
1227 int rc = __iface_cmdq_write_relaxed(device, pkt, &needs_interrupt);
1228
1229 if (!rc && needs_interrupt) {
1230 /* Consumer of cmdq prefers that we raise an interrupt */
1231 rc = 0;
1232 __write_register(device, VIDC_CPU_IC_SOFTINT,
1233 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT);
1234 }
1235
1236 return rc;
1237}
1238
1239static int __iface_msgq_read(struct venus_hfi_device *device, void *pkt)
1240{
1241 u32 tx_req_is_set = 0;
1242 int rc = 0;
1243 struct vidc_iface_q_info *q_info;
1244
1245 if (!pkt) {
1246 dprintk(VIDC_ERR, "Invalid Params\n");
1247 return -EINVAL;
1248 }
1249
1250 __strict_check(device);
1251
1252 if (!__core_in_valid_state(device)) {
1253 dprintk(VIDC_DBG, "%s - fw not in init state\n", __func__);
1254 rc = -EINVAL;
1255 goto read_error_null;
1256 }
1257
1258 if (device->iface_queues[VIDC_IFACEQ_MSGQ_IDX].
1259 q_array.align_virtual_addr == 0) {
1260 dprintk(VIDC_ERR, "cannot read from shared MSG Q's\n");
1261 rc = -ENODATA;
1262 goto read_error_null;
1263 }
1264
1265 q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
1266 if (!__read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
1267 __hal_sim_modify_msg_packet((u8 *)pkt, device);
1268 if (tx_req_is_set)
1269 __write_register(device, VIDC_CPU_IC_SOFTINT,
1270 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT);
1271 rc = 0;
1272 } else
1273 rc = -ENODATA;
1274
1275read_error_null:
1276 return rc;
1277}
1278
1279static int __iface_dbgq_read(struct venus_hfi_device *device, void *pkt)
1280{
1281 u32 tx_req_is_set = 0;
1282 int rc = 0;
1283 struct vidc_iface_q_info *q_info;
1284
1285 if (!pkt) {
1286 dprintk(VIDC_ERR, "Invalid Params\n");
1287 return -EINVAL;
1288 }
1289
1290 __strict_check(device);
1291
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08001292 if (device->iface_queues[VIDC_IFACEQ_DBGQ_IDX].
1293 q_array.align_virtual_addr == 0) {
1294 dprintk(VIDC_ERR, "cannot read from shared DBG Q's\n");
1295 rc = -ENODATA;
1296 goto dbg_error_null;
1297 }
1298
1299 q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
1300 if (!__read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
1301 if (tx_req_is_set)
1302 __write_register(device, VIDC_CPU_IC_SOFTINT,
1303 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT);
1304 rc = 0;
1305 } else
1306 rc = -ENODATA;
1307
1308dbg_error_null:
1309 return rc;
1310}
1311
1312static void __set_queue_hdr_defaults(struct hfi_queue_header *q_hdr)
1313{
1314 q_hdr->qhdr_status = 0x1;
1315 q_hdr->qhdr_type = VIDC_IFACEQ_DFLT_QHDR;
1316 q_hdr->qhdr_q_size = VIDC_IFACEQ_QUEUE_SIZE / 4;
1317 q_hdr->qhdr_pkt_size = 0;
1318 q_hdr->qhdr_rx_wm = 0x1;
1319 q_hdr->qhdr_tx_wm = 0x1;
1320 q_hdr->qhdr_rx_req = 0x1;
1321 q_hdr->qhdr_tx_req = 0x0;
1322 q_hdr->qhdr_rx_irq_status = 0x0;
1323 q_hdr->qhdr_tx_irq_status = 0x0;
1324 q_hdr->qhdr_read_idx = 0x0;
1325 q_hdr->qhdr_write_idx = 0x0;
1326}
1327
1328static void __interface_queues_release(struct venus_hfi_device *device)
1329{
1330 int i;
1331 struct hfi_mem_map_table *qdss;
1332 struct hfi_mem_map *mem_map;
1333 int num_entries = device->res->qdss_addr_set.count;
1334 unsigned long mem_map_table_base_addr;
1335 struct context_bank_info *cb;
1336
1337 if (device->qdss.mem_data) {
1338 qdss = (struct hfi_mem_map_table *)
1339 device->qdss.align_virtual_addr;
1340 qdss->mem_map_num_entries = num_entries;
1341 mem_map_table_base_addr =
1342 device->qdss.align_device_addr +
1343 sizeof(struct hfi_mem_map_table);
1344 qdss->mem_map_table_base_addr =
1345 (u32)mem_map_table_base_addr;
1346 if ((unsigned long)qdss->mem_map_table_base_addr !=
1347 mem_map_table_base_addr) {
1348 dprintk(VIDC_ERR,
1349 "Invalid mem_map_table_base_addr %#lx",
1350 mem_map_table_base_addr);
1351 }
1352
1353 mem_map = (struct hfi_mem_map *)(qdss + 1);
1354 cb = msm_smem_get_context_bank(device->hal_client,
1355 false, HAL_BUFFER_INTERNAL_CMD_QUEUE);
1356
1357 for (i = 0; cb && i < num_entries; i++) {
1358 iommu_unmap(cb->mapping->domain,
1359 mem_map[i].virtual_addr,
1360 mem_map[i].size);
1361 }
1362
1363 __smem_free(device, device->qdss.mem_data);
1364 }
1365
1366 __smem_free(device, device->iface_q_table.mem_data);
1367 __smem_free(device, device->sfr.mem_data);
1368
1369 for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
1370 device->iface_queues[i].q_hdr = NULL;
1371 device->iface_queues[i].q_array.mem_data = NULL;
1372 device->iface_queues[i].q_array.align_virtual_addr = NULL;
1373 device->iface_queues[i].q_array.align_device_addr = 0;
1374 }
1375
1376 device->iface_q_table.mem_data = NULL;
1377 device->iface_q_table.align_virtual_addr = NULL;
1378 device->iface_q_table.align_device_addr = 0;
1379
1380 device->qdss.mem_data = NULL;
1381 device->qdss.align_virtual_addr = NULL;
1382 device->qdss.align_device_addr = 0;
1383
1384 device->sfr.mem_data = NULL;
1385 device->sfr.align_virtual_addr = NULL;
1386 device->sfr.align_device_addr = 0;
1387
1388 device->mem_addr.mem_data = NULL;
1389 device->mem_addr.align_virtual_addr = NULL;
1390 device->mem_addr.align_device_addr = 0;
1391
1392 msm_smem_delete_client(device->hal_client);
1393 device->hal_client = NULL;
1394}
1395
1396static int __get_qdss_iommu_virtual_addr(struct venus_hfi_device *dev,
1397 struct hfi_mem_map *mem_map, struct dma_iommu_mapping *mapping)
1398{
1399 int i;
1400 int rc = 0;
1401 dma_addr_t iova = QDSS_IOVA_START;
1402 int num_entries = dev->res->qdss_addr_set.count;
1403 struct addr_range *qdss_addr_tbl = dev->res->qdss_addr_set.addr_tbl;
1404
1405 if (!num_entries)
1406 return -ENODATA;
1407
1408 for (i = 0; i < num_entries; i++) {
1409 if (mapping) {
1410 rc = iommu_map(mapping->domain, iova,
1411 qdss_addr_tbl[i].start,
1412 qdss_addr_tbl[i].size,
1413 IOMMU_READ | IOMMU_WRITE);
1414
1415 if (rc) {
1416 dprintk(VIDC_ERR,
1417 "IOMMU QDSS mapping failed for addr %#x\n",
1418 qdss_addr_tbl[i].start);
1419 rc = -ENOMEM;
1420 break;
1421 }
1422 } else {
1423 iova = qdss_addr_tbl[i].start;
1424 }
1425
1426 mem_map[i].virtual_addr = (u32)iova;
1427 mem_map[i].physical_addr = qdss_addr_tbl[i].start;
1428 mem_map[i].size = qdss_addr_tbl[i].size;
1429 mem_map[i].attr = 0x0;
1430
1431 iova += mem_map[i].size;
1432 }
1433
1434 if (i < num_entries) {
1435 dprintk(VIDC_ERR,
1436 "QDSS mapping failed, Freeing other entries %d\n", i);
1437
1438 for (--i; mapping && i >= 0; i--) {
1439 iommu_unmap(mapping->domain,
1440 mem_map[i].virtual_addr,
1441 mem_map[i].size);
1442 }
1443 }
1444
1445 return rc;
1446}
1447
1448static void __setup_ucregion_memory_map(struct venus_hfi_device *device)
1449{
1450 __write_register(device, VIDC_UC_REGION_ADDR,
1451 (u32)device->iface_q_table.align_device_addr);
1452 __write_register(device, VIDC_UC_REGION_SIZE, SHARED_QSIZE);
1453 __write_register(device, VIDC_CPU_CS_SCIACMDARG2,
1454 (u32)device->iface_q_table.align_device_addr);
1455 __write_register(device, VIDC_CPU_CS_SCIACMDARG1, 0x01);
1456 if (device->sfr.align_device_addr)
1457 __write_register(device, VIDC_SFR_ADDR,
1458 (u32)device->sfr.align_device_addr);
1459 if (device->qdss.align_device_addr)
1460 __write_register(device, VIDC_MMAP_ADDR,
1461 (u32)device->qdss.align_device_addr);
1462}
1463
1464static int __interface_queues_init(struct venus_hfi_device *dev)
1465{
1466 struct hfi_queue_table_header *q_tbl_hdr;
1467 struct hfi_queue_header *q_hdr;
1468 u32 i;
1469 int rc = 0;
1470 struct hfi_mem_map_table *qdss;
1471 struct hfi_mem_map *mem_map;
1472 struct vidc_iface_q_info *iface_q;
1473 struct hfi_sfr_struct *vsfr;
1474 struct vidc_mem_addr *mem_addr;
1475 int offset = 0;
1476 int num_entries = dev->res->qdss_addr_set.count;
1477 u32 value = 0;
1478 phys_addr_t fw_bias = 0;
1479 size_t q_size;
1480 unsigned long mem_map_table_base_addr;
1481 struct context_bank_info *cb;
1482
1483 q_size = SHARED_QSIZE - ALIGNED_SFR_SIZE - ALIGNED_QDSS_SIZE;
1484 mem_addr = &dev->mem_addr;
1485 if (!is_iommu_present(dev->res))
1486 fw_bias = dev->hal_data->firmware_base;
1487 rc = __smem_alloc(dev, mem_addr, q_size, 1, 0,
1488 HAL_BUFFER_INTERNAL_CMD_QUEUE);
1489 if (rc) {
1490 dprintk(VIDC_ERR, "iface_q_table_alloc_fail\n");
1491 goto fail_alloc_queue;
1492 }
1493
1494 dev->iface_q_table.align_virtual_addr = mem_addr->align_virtual_addr;
1495 dev->iface_q_table.align_device_addr = mem_addr->align_device_addr -
1496 fw_bias;
1497 dev->iface_q_table.mem_size = VIDC_IFACEQ_TABLE_SIZE;
1498 dev->iface_q_table.mem_data = mem_addr->mem_data;
1499 offset += dev->iface_q_table.mem_size;
1500
1501 for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) {
1502 iface_q = &dev->iface_queues[i];
1503 iface_q->q_array.align_device_addr = mem_addr->align_device_addr
1504 + offset - fw_bias;
1505 iface_q->q_array.align_virtual_addr =
1506 mem_addr->align_virtual_addr + offset;
1507 iface_q->q_array.mem_size = VIDC_IFACEQ_QUEUE_SIZE;
1508 iface_q->q_array.mem_data = NULL;
1509 offset += iface_q->q_array.mem_size;
1510 iface_q->q_hdr = VIDC_IFACEQ_GET_QHDR_START_ADDR(
1511 dev->iface_q_table.align_virtual_addr, i);
1512 __set_queue_hdr_defaults(iface_q->q_hdr);
1513 }
1514
1515 if ((msm_vidc_fw_debug_mode & HFI_DEBUG_MODE_QDSS) && num_entries) {
1516 rc = __smem_alloc(dev, mem_addr,
1517 ALIGNED_QDSS_SIZE, 1, 0,
1518 HAL_BUFFER_INTERNAL_CMD_QUEUE);
1519 if (rc) {
1520 dprintk(VIDC_WARN,
1521 "qdss_alloc_fail: QDSS messages logging will not work\n");
1522 dev->qdss.align_device_addr = 0;
1523 } else {
1524 dev->qdss.align_device_addr =
1525 mem_addr->align_device_addr - fw_bias;
1526 dev->qdss.align_virtual_addr =
1527 mem_addr->align_virtual_addr;
1528 dev->qdss.mem_size = ALIGNED_QDSS_SIZE;
1529 dev->qdss.mem_data = mem_addr->mem_data;
1530 }
1531 }
1532
1533 rc = __smem_alloc(dev, mem_addr,
1534 ALIGNED_SFR_SIZE, 1, 0,
1535 HAL_BUFFER_INTERNAL_CMD_QUEUE);
1536 if (rc) {
1537 dprintk(VIDC_WARN, "sfr_alloc_fail: SFR not will work\n");
1538 dev->sfr.align_device_addr = 0;
1539 } else {
1540 dev->sfr.align_device_addr = mem_addr->align_device_addr -
1541 fw_bias;
1542 dev->sfr.align_virtual_addr = mem_addr->align_virtual_addr;
1543 dev->sfr.mem_size = ALIGNED_SFR_SIZE;
1544 dev->sfr.mem_data = mem_addr->mem_data;
1545 }
1546
1547 q_tbl_hdr = (struct hfi_queue_table_header *)
1548 dev->iface_q_table.align_virtual_addr;
1549 q_tbl_hdr->qtbl_version = 0;
1550 q_tbl_hdr->device_addr = (void *)dev;
1551 strlcpy(q_tbl_hdr->name, "msm_v4l2_vidc", sizeof(q_tbl_hdr->name));
1552 q_tbl_hdr->qtbl_size = VIDC_IFACEQ_TABLE_SIZE;
1553 q_tbl_hdr->qtbl_qhdr0_offset = sizeof(struct hfi_queue_table_header);
1554 q_tbl_hdr->qtbl_qhdr_size = sizeof(struct hfi_queue_header);
1555 q_tbl_hdr->qtbl_num_q = VIDC_IFACEQ_NUMQ;
1556 q_tbl_hdr->qtbl_num_active_q = VIDC_IFACEQ_NUMQ;
1557
1558 iface_q = &dev->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
1559 q_hdr = iface_q->q_hdr;
1560 q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr;
1561 q_hdr->qhdr_type |= HFI_Q_ID_HOST_TO_CTRL_CMD_Q;
1562 if ((ion_phys_addr_t)q_hdr->qhdr_start_addr !=
1563 iface_q->q_array.align_device_addr) {
1564 dprintk(VIDC_ERR, "Invalid CMDQ device address (%pa)",
1565 &iface_q->q_array.align_device_addr);
1566 }
1567
1568 iface_q = &dev->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
1569 q_hdr = iface_q->q_hdr;
1570 q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr;
1571 q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_MSG_Q;
1572 if ((ion_phys_addr_t)q_hdr->qhdr_start_addr !=
1573 iface_q->q_array.align_device_addr) {
1574 dprintk(VIDC_ERR, "Invalid MSGQ device address (%pa)",
1575 &iface_q->q_array.align_device_addr);
1576 }
1577
1578 iface_q = &dev->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
1579 q_hdr = iface_q->q_hdr;
1580 q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr;
1581 q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q;
1582 /*
1583 * Set receive request to zero on debug queue as there is no
1584 * need of interrupt from video hardware for debug messages
1585 */
1586 q_hdr->qhdr_rx_req = 0;
1587 if ((ion_phys_addr_t)q_hdr->qhdr_start_addr !=
1588 iface_q->q_array.align_device_addr) {
1589 dprintk(VIDC_ERR, "Invalid DBGQ device address (%pa)",
1590 &iface_q->q_array.align_device_addr);
1591 }
1592
1593 value = (u32)dev->iface_q_table.align_device_addr;
1594 if ((ion_phys_addr_t)value !=
1595 dev->iface_q_table.align_device_addr) {
1596 dprintk(VIDC_ERR,
1597 "Invalid iface_q_table device address (%pa)",
1598 &dev->iface_q_table.align_device_addr);
1599 }
1600
1601 if (dev->qdss.mem_data) {
1602 qdss = (struct hfi_mem_map_table *)dev->qdss.align_virtual_addr;
1603 qdss->mem_map_num_entries = num_entries;
1604 mem_map_table_base_addr = dev->qdss.align_device_addr +
1605 sizeof(struct hfi_mem_map_table);
1606 qdss->mem_map_table_base_addr =
1607 (u32)mem_map_table_base_addr;
1608 if ((ion_phys_addr_t)qdss->mem_map_table_base_addr !=
1609 mem_map_table_base_addr) {
1610 dprintk(VIDC_ERR,
1611 "Invalid mem_map_table_base_addr (%#lx)",
1612 mem_map_table_base_addr);
1613 }
1614
1615 mem_map = (struct hfi_mem_map *)(qdss + 1);
1616 cb = msm_smem_get_context_bank(dev->hal_client, false,
1617 HAL_BUFFER_INTERNAL_CMD_QUEUE);
1618
1619 if (!cb) {
1620 dprintk(VIDC_ERR,
1621 "%s: failed to get context bank\n", __func__);
1622 return -EINVAL;
1623 }
1624
1625 rc = __get_qdss_iommu_virtual_addr(dev, mem_map, cb->mapping);
1626 if (rc) {
1627 dprintk(VIDC_ERR,
1628 "IOMMU mapping failed, Freeing qdss memdata\n");
1629 __smem_free(dev, dev->qdss.mem_data);
1630 dev->qdss.mem_data = NULL;
1631 dev->qdss.align_virtual_addr = NULL;
1632 dev->qdss.align_device_addr = 0;
1633 }
1634
1635 value = (u32)dev->qdss.align_device_addr;
1636 if ((ion_phys_addr_t)value !=
1637 dev->qdss.align_device_addr) {
1638 dprintk(VIDC_ERR, "Invalid qdss device address (%pa)",
1639 &dev->qdss.align_device_addr);
1640 }
1641 }
1642
1643 vsfr = (struct hfi_sfr_struct *) dev->sfr.align_virtual_addr;
1644 vsfr->bufSize = ALIGNED_SFR_SIZE;
1645 value = (u32)dev->sfr.align_device_addr;
1646 if ((ion_phys_addr_t)value !=
1647 dev->sfr.align_device_addr) {
1648 dprintk(VIDC_ERR, "Invalid sfr device address (%pa)",
1649 &dev->sfr.align_device_addr);
1650 }
1651
1652 __setup_ucregion_memory_map(dev);
1653 return 0;
1654fail_alloc_queue:
1655 return -ENOMEM;
1656}
1657
1658static int __sys_set_debug(struct venus_hfi_device *device, u32 debug)
1659{
1660 u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
1661 int rc = 0;
1662 struct hfi_cmd_sys_set_property_packet *pkt =
1663 (struct hfi_cmd_sys_set_property_packet *) &packet;
1664
1665 rc = call_hfi_pkt_op(device, sys_debug_config, pkt, debug);
1666 if (rc) {
1667 dprintk(VIDC_WARN,
1668 "Debug mode setting to FW failed\n");
1669 return -ENOTEMPTY;
1670 }
1671
1672 if (__iface_cmdq_write(device, pkt))
1673 return -ENOTEMPTY;
1674 return 0;
1675}
1676
1677static int __sys_set_coverage(struct venus_hfi_device *device, u32 mode)
1678{
1679 u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
1680 int rc = 0;
1681 struct hfi_cmd_sys_set_property_packet *pkt =
1682 (struct hfi_cmd_sys_set_property_packet *) &packet;
1683
1684 rc = call_hfi_pkt_op(device, sys_coverage_config,
1685 pkt, mode);
1686 if (rc) {
1687 dprintk(VIDC_WARN,
1688 "Coverage mode setting to FW failed\n");
1689 return -ENOTEMPTY;
1690 }
1691
1692 if (__iface_cmdq_write(device, pkt)) {
1693 dprintk(VIDC_WARN, "Failed to send coverage pkt to f/w\n");
1694 return -ENOTEMPTY;
1695 }
1696
1697 return 0;
1698}
1699
1700static int __sys_set_idle_message(struct venus_hfi_device *device,
1701 bool enable)
1702{
1703 u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
1704 struct hfi_cmd_sys_set_property_packet *pkt =
1705 (struct hfi_cmd_sys_set_property_packet *) &packet;
1706
1707 if (!enable) {
1708 dprintk(VIDC_DBG, "sys_idle_indicator is not enabled\n");
1709 return 0;
1710 }
1711
1712 call_hfi_pkt_op(device, sys_idle_indicator, pkt, enable);
1713 if (__iface_cmdq_write(device, pkt))
1714 return -ENOTEMPTY;
1715 return 0;
1716}
1717
1718static int __sys_set_power_control(struct venus_hfi_device *device,
1719 bool enable)
1720{
1721 struct regulator_info *rinfo;
1722 bool supported = false;
1723 u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE];
1724 struct hfi_cmd_sys_set_property_packet *pkt =
1725 (struct hfi_cmd_sys_set_property_packet *) &packet;
1726
1727 venus_hfi_for_each_regulator(device, rinfo) {
1728 if (rinfo->has_hw_power_collapse) {
1729 supported = true;
1730 break;
1731 }
1732 }
1733
1734 if (!supported)
1735 return 0;
1736
1737 call_hfi_pkt_op(device, sys_power_control, pkt, enable);
1738 if (__iface_cmdq_write(device, pkt))
1739 return -ENOTEMPTY;
1740 return 0;
1741}
1742
1743static int venus_hfi_core_init(void *device)
1744{
1745 struct hfi_cmd_sys_init_packet pkt;
1746 struct hfi_cmd_sys_get_property_packet version_pkt;
1747 int rc = 0;
1748 struct list_head *ptr, *next;
1749 struct hal_session *session = NULL;
1750 struct venus_hfi_device *dev;
1751
1752 if (!device) {
1753 dprintk(VIDC_ERR, "Invalid device\n");
1754 return -ENODEV;
1755 }
1756
1757 dev = device;
1758 mutex_lock(&dev->lock);
1759
1760 rc = __load_fw(dev);
1761 if (rc) {
1762 dprintk(VIDC_ERR, "Failed to load Venus FW\n");
1763 goto err_load_fw;
1764 }
1765
1766 __set_state(dev, VENUS_STATE_INIT);
1767
1768 list_for_each_safe(ptr, next, &dev->sess_head) {
1769 /*
1770 * This means that session list is not empty. Kick stale
1771 * sessions out of our valid instance list, but keep the
1772 * list_head inited so that list_del (in the future, called
1773 * by session_clean()) will be valid. When client doesn't close
1774 * them, then it is a genuine leak which driver can't fix.
1775 */
1776 session = list_entry(ptr, struct hal_session, list);
1777 list_del_init(&session->list);
1778 }
1779
1780 INIT_LIST_HEAD(&dev->sess_head);
1781
1782 if (!dev->hal_client) {
1783 dev->hal_client = msm_smem_new_client(
1784 SMEM_ION, dev->res, MSM_VIDC_UNKNOWN);
1785 if (dev->hal_client == NULL) {
1786 dprintk(VIDC_ERR, "Failed to alloc ION_Client\n");
1787 rc = -ENODEV;
1788 goto err_core_init;
1789 }
1790
1791 dprintk(VIDC_DBG, "Dev_Virt: %pa, Reg_Virt: %pK\n",
1792 &dev->hal_data->firmware_base,
1793 dev->hal_data->register_base);
1794
1795 rc = __interface_queues_init(dev);
1796 if (rc) {
1797 dprintk(VIDC_ERR, "failed to init queues\n");
1798 rc = -ENOMEM;
1799 goto err_core_init;
1800 }
1801 } else {
1802 dprintk(VIDC_ERR, "hal_client exists\n");
1803 rc = -EEXIST;
1804 goto err_core_init;
1805 }
1806
1807 rc = __boot_firmware(dev);
1808 if (rc) {
1809 dprintk(VIDC_ERR, "Failed to start core\n");
1810 rc = -ENODEV;
1811 goto err_core_init;
1812 }
1813
1814 rc = call_hfi_pkt_op(dev, sys_init, &pkt, HFI_VIDEO_ARCH_OX);
1815 if (rc) {
1816 dprintk(VIDC_ERR, "Failed to create sys init pkt\n");
1817 goto err_core_init;
1818 }
1819
1820 if (__iface_cmdq_write(dev, &pkt)) {
1821 rc = -ENOTEMPTY;
1822 goto err_core_init;
1823 }
1824
1825 rc = call_hfi_pkt_op(dev, sys_image_version, &version_pkt);
1826 if (rc || __iface_cmdq_write(dev, &version_pkt))
1827 dprintk(VIDC_WARN, "Failed to send image version pkt to f/w\n");
1828
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -07001829 rc = __enable_subcaches(device);
1830 if (rc) {
1831 dprintk(VIDC_WARN,
1832 "Failed to enable subcaches, err = %d\n", rc);
1833 }
1834
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08001835 if (dev->res->pm_qos_latency_us) {
1836#ifdef CONFIG_SMP
1837 dev->qos.type = PM_QOS_REQ_AFFINE_IRQ;
1838 dev->qos.irq = dev->hal_data->irq;
1839#endif
1840 pm_qos_add_request(&dev->qos, PM_QOS_CPU_DMA_LATENCY,
1841 dev->res->pm_qos_latency_us);
1842 }
1843
1844 mutex_unlock(&dev->lock);
1845 return rc;
1846err_core_init:
1847 __set_state(dev, VENUS_STATE_DEINIT);
1848 __unload_fw(dev);
1849err_load_fw:
1850 mutex_unlock(&dev->lock);
1851 return rc;
1852}
1853
1854static int venus_hfi_core_release(void *dev)
1855{
1856 struct venus_hfi_device *device = dev;
1857 int rc = 0;
1858
1859 if (!device) {
1860 dprintk(VIDC_ERR, "invalid device\n");
1861 return -ENODEV;
1862 }
1863
1864 mutex_lock(&device->lock);
1865
1866 if (device->res->pm_qos_latency_us &&
1867 pm_qos_request_active(&device->qos))
1868 pm_qos_remove_request(&device->qos);
Maheshwar Ajjae43dd822017-04-25 15:56:53 -07001869
1870 __resume(device);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08001871 __set_state(device, VENUS_STATE_DEINIT);
1872 __unload_fw(device);
1873
1874 mutex_unlock(&device->lock);
1875
1876 return rc;
1877}
1878
1879static int __get_q_size(struct venus_hfi_device *dev, unsigned int q_index)
1880{
1881 struct hfi_queue_header *queue;
1882 struct vidc_iface_q_info *q_info;
1883 u32 write_ptr, read_ptr;
1884
1885 if (q_index >= VIDC_IFACEQ_NUMQ) {
1886 dprintk(VIDC_ERR, "Invalid q index: %d\n", q_index);
1887 return -ENOENT;
1888 }
1889
1890 q_info = &dev->iface_queues[q_index];
1891 if (!q_info) {
1892 dprintk(VIDC_ERR, "cannot read shared Q's\n");
1893 return -ENOENT;
1894 }
1895
1896 queue = (struct hfi_queue_header *)q_info->q_hdr;
1897 if (!queue) {
1898 dprintk(VIDC_ERR, "queue not present\n");
1899 return -ENOENT;
1900 }
1901
1902 write_ptr = (u32)queue->qhdr_write_idx;
1903 read_ptr = (u32)queue->qhdr_read_idx;
1904 return read_ptr - write_ptr;
1905}
1906
1907static void __core_clear_interrupt(struct venus_hfi_device *device)
1908{
1909 u32 intr_status = 0;
1910
1911 if (!device) {
1912 dprintk(VIDC_ERR, "%s: NULL device\n", __func__);
1913 return;
1914 }
1915
1916 intr_status = __read_register(device, VIDC_WRAPPER_INTR_STATUS);
1917
1918 if (intr_status & VIDC_WRAPPER_INTR_STATUS_A2H_BMSK ||
1919 intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK ||
1920 intr_status &
1921 VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK) {
1922 device->intr_status |= intr_status;
1923 device->reg_count++;
1924 dprintk(VIDC_DBG,
1925 "INTERRUPT for device: %pK: times: %d interrupt_status: %d\n",
1926 device, device->reg_count, intr_status);
1927 } else {
1928 device->spur_count++;
1929 dprintk(VIDC_INFO,
1930 "SPURIOUS_INTR for device: %pK: times: %d interrupt_status: %d\n",
1931 device, device->spur_count, intr_status);
1932 }
1933
1934 __write_register(device, VIDC_CPU_CS_A2HSOFTINTCLR, 1);
1935 __write_register(device, VIDC_WRAPPER_INTR_CLEAR, intr_status);
1936 dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt\n");
1937}
1938
1939static int venus_hfi_core_ping(void *device)
1940{
1941 struct hfi_cmd_sys_ping_packet pkt;
1942 int rc = 0;
1943 struct venus_hfi_device *dev;
1944
1945 if (!device) {
1946 dprintk(VIDC_ERR, "invalid device\n");
1947 return -ENODEV;
1948 }
1949
1950 dev = device;
1951 mutex_lock(&dev->lock);
1952
1953 rc = call_hfi_pkt_op(dev, sys_ping, &pkt);
1954 if (rc) {
1955 dprintk(VIDC_ERR, "core_ping: failed to create packet\n");
1956 goto err_create_pkt;
1957 }
1958
1959 if (__iface_cmdq_write(dev, &pkt))
1960 rc = -ENOTEMPTY;
1961
1962err_create_pkt:
1963 mutex_unlock(&dev->lock);
1964 return rc;
1965}
1966
1967static int venus_hfi_core_trigger_ssr(void *device,
1968 enum hal_ssr_trigger_type type)
1969{
1970 struct hfi_cmd_sys_test_ssr_packet pkt;
1971 int rc = 0;
1972 struct venus_hfi_device *dev;
1973
1974 if (!device) {
1975 dprintk(VIDC_ERR, "invalid device\n");
1976 return -ENODEV;
1977 }
1978
1979 dev = device;
1980 mutex_lock(&dev->lock);
1981
1982 rc = call_hfi_pkt_op(dev, ssr_cmd, type, &pkt);
1983 if (rc) {
1984 dprintk(VIDC_ERR, "core_ping: failed to create packet\n");
1985 goto err_create_pkt;
1986 }
1987
1988 if (__iface_cmdq_write(dev, &pkt))
1989 rc = -ENOTEMPTY;
1990
1991err_create_pkt:
1992 mutex_unlock(&dev->lock);
1993 return rc;
1994}
1995
1996static int venus_hfi_session_set_property(void *sess,
1997 enum hal_property ptype, void *pdata)
1998{
1999 u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
2000 struct hfi_cmd_session_set_property_packet *pkt =
2001 (struct hfi_cmd_session_set_property_packet *) &packet;
2002 struct hal_session *session = sess;
2003 struct venus_hfi_device *device;
2004 int rc = 0;
2005
2006 if (!session || !session->device || !pdata) {
2007 dprintk(VIDC_ERR, "Invalid Params\n");
2008 return -EINVAL;
2009 }
2010
2011 device = session->device;
2012 mutex_lock(&device->lock);
2013
2014 dprintk(VIDC_INFO, "in set_prop,with prop id: %#x\n", ptype);
2015
2016 rc = call_hfi_pkt_op(device, session_set_property,
2017 pkt, session, ptype, pdata);
2018
2019 if (rc == -ENOTSUPP) {
2020 dprintk(VIDC_DBG,
2021 "set property: unsupported prop id: %#x\n", ptype);
2022 rc = 0;
2023 goto err_set_prop;
2024 } else if (rc) {
2025 dprintk(VIDC_ERR, "set property: failed to create packet\n");
2026 rc = -EINVAL;
2027 goto err_set_prop;
2028 }
2029
2030 if (__iface_cmdq_write(session->device, pkt)) {
2031 rc = -ENOTEMPTY;
2032 goto err_set_prop;
2033 }
2034
2035err_set_prop:
2036 mutex_unlock(&device->lock);
2037 return rc;
2038}
2039
2040static int venus_hfi_session_get_property(void *sess,
2041 enum hal_property ptype)
2042{
2043 struct hfi_cmd_session_get_property_packet pkt = {0};
2044 struct hal_session *session = sess;
2045 int rc = 0;
2046 struct venus_hfi_device *device;
2047
2048 if (!session || !session->device) {
2049 dprintk(VIDC_ERR, "Invalid Params\n");
2050 return -EINVAL;
2051 }
2052
2053 device = session->device;
2054 mutex_lock(&device->lock);
2055
2056 dprintk(VIDC_INFO, "%s: property id: %d\n", __func__, ptype);
2057
2058 rc = call_hfi_pkt_op(device, session_get_property,
2059 &pkt, session, ptype);
2060 if (rc) {
2061 dprintk(VIDC_ERR, "get property profile: pkt failed\n");
2062 goto err_create_pkt;
2063 }
2064
2065 if (__iface_cmdq_write(session->device, &pkt)) {
2066 rc = -ENOTEMPTY;
2067 dprintk(VIDC_ERR, "%s cmdq_write error\n", __func__);
2068 }
2069
2070err_create_pkt:
2071 mutex_unlock(&device->lock);
2072 return rc;
2073}
2074
2075static void __set_default_sys_properties(struct venus_hfi_device *device)
2076{
2077 if (__sys_set_debug(device, msm_vidc_fw_debug))
2078 dprintk(VIDC_WARN, "Setting fw_debug msg ON failed\n");
2079 if (__sys_set_idle_message(device,
2080 device->res->sys_idle_indicator || msm_vidc_sys_idle_indicator))
2081 dprintk(VIDC_WARN, "Setting idle response ON failed\n");
2082 if (__sys_set_power_control(device, msm_vidc_fw_low_power_mode))
2083 dprintk(VIDC_WARN, "Setting h/w power collapse ON failed\n");
2084}
2085
2086static void __session_clean(struct hal_session *session)
2087{
2088 dprintk(VIDC_DBG, "deleted the session: %pK\n", session);
2089 list_del(&session->list);
2090 /* Poison the session handle with zeros */
2091 *session = (struct hal_session){ {0} };
2092 kfree(session);
2093}
2094
2095static int venus_hfi_session_clean(void *session)
2096{
2097 struct hal_session *sess_close;
2098 struct venus_hfi_device *device;
2099
2100 if (!session) {
2101 dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
2102 return -EINVAL;
2103 }
2104
2105 sess_close = session;
2106 device = sess_close->device;
2107
2108 if (!device) {
2109 dprintk(VIDC_ERR, "Invalid device handle %s\n", __func__);
2110 return -EINVAL;
2111 }
2112
2113 mutex_lock(&device->lock);
2114
2115 __session_clean(sess_close);
2116
2117 mutex_unlock(&device->lock);
2118 return 0;
2119}
2120
2121static int venus_hfi_session_init(void *device, void *session_id,
2122 enum hal_domain session_type, enum hal_video_codec codec_type,
2123 void **new_session)
2124{
2125 struct hfi_cmd_sys_session_init_packet pkt;
2126 struct venus_hfi_device *dev;
2127 struct hal_session *s;
2128
2129 if (!device || !new_session) {
2130 dprintk(VIDC_ERR, "%s - invalid input\n", __func__);
2131 return -EINVAL;
2132 }
2133
2134 dev = device;
2135 mutex_lock(&dev->lock);
2136
2137 s = kzalloc(sizeof(struct hal_session), GFP_KERNEL);
2138 if (!s) {
2139 dprintk(VIDC_ERR, "new session fail: Out of memory\n");
2140 goto err_session_init_fail;
2141 }
2142
2143 s->session_id = session_id;
2144 s->is_decoder = (session_type == HAL_VIDEO_DOMAIN_DECODER);
2145 s->device = dev;
2146 s->codec = codec_type;
2147 s->domain = session_type;
2148 dprintk(VIDC_DBG,
2149 "%s: inst %pK, session %pK, codec 0x%x, domain 0x%x\n",
2150 __func__, session_id, s, s->codec, s->domain);
2151
2152 list_add_tail(&s->list, &dev->sess_head);
2153
2154 __set_default_sys_properties(device);
2155
2156 if (call_hfi_pkt_op(dev, session_init, &pkt,
2157 s, session_type, codec_type)) {
2158 dprintk(VIDC_ERR, "session_init: failed to create packet\n");
2159 goto err_session_init_fail;
2160 }
2161
2162 *new_session = s;
2163 if (__iface_cmdq_write(dev, &pkt))
2164 goto err_session_init_fail;
2165
2166 mutex_unlock(&dev->lock);
2167 return 0;
2168
2169err_session_init_fail:
2170 if (s)
2171 __session_clean(s);
2172 *new_session = NULL;
2173 mutex_unlock(&dev->lock);
2174 return -EINVAL;
2175}
2176
2177static int __send_session_cmd(struct hal_session *session, int pkt_type)
2178{
2179 struct vidc_hal_session_cmd_pkt pkt;
2180 int rc = 0;
2181 struct venus_hfi_device *device = session->device;
2182
2183 rc = call_hfi_pkt_op(device, session_cmd,
2184 &pkt, pkt_type, session);
2185 if (rc == -EPERM)
2186 return 0;
2187
2188 if (rc) {
2189 dprintk(VIDC_ERR, "send session cmd: create pkt failed\n");
2190 goto err_create_pkt;
2191 }
2192
2193 if (__iface_cmdq_write(session->device, &pkt))
2194 rc = -ENOTEMPTY;
2195
2196err_create_pkt:
2197 return rc;
2198}
2199
2200static int venus_hfi_session_end(void *session)
2201{
2202 struct hal_session *sess;
2203 struct venus_hfi_device *device;
2204 int rc = 0;
2205
2206 if (!session) {
2207 dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
2208 return -EINVAL;
2209 }
2210
2211 sess = session;
2212 device = sess->device;
2213
2214 mutex_lock(&device->lock);
2215
2216 if (msm_vidc_fw_coverage) {
2217 if (__sys_set_coverage(sess->device, msm_vidc_fw_coverage))
2218 dprintk(VIDC_WARN, "Fw_coverage msg ON failed\n");
2219 }
2220
2221 rc = __send_session_cmd(session, HFI_CMD_SYS_SESSION_END);
2222
2223 mutex_unlock(&device->lock);
2224
2225 return rc;
2226}
2227
2228static int venus_hfi_session_abort(void *sess)
2229{
2230 struct hal_session *session = sess;
2231 struct venus_hfi_device *device;
2232 int rc = 0;
2233
2234 if (!session || !session->device) {
2235 dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
2236 return -EINVAL;
2237 }
2238
2239 device = session->device;
2240
2241 mutex_lock(&device->lock);
2242
2243 __flush_debug_queue(device, NULL);
2244 rc = __send_session_cmd(session, HFI_CMD_SYS_SESSION_ABORT);
2245
2246 mutex_unlock(&device->lock);
2247
2248 return rc;
2249}
2250
2251static int venus_hfi_session_set_buffers(void *sess,
2252 struct vidc_buffer_addr_info *buffer_info)
2253{
2254 struct hfi_cmd_session_set_buffers_packet *pkt;
2255 u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
2256 int rc = 0;
2257 struct hal_session *session = sess;
2258 struct venus_hfi_device *device;
2259
2260 if (!session || !session->device || !buffer_info) {
2261 dprintk(VIDC_ERR, "Invalid Params\n");
2262 return -EINVAL;
2263 }
2264
2265 device = session->device;
2266 mutex_lock(&device->lock);
2267
2268 if (buffer_info->buffer_type == HAL_BUFFER_INPUT) {
2269 /*
2270 * Hardware doesn't care about input buffers being
2271 * published beforehand
2272 */
2273 rc = 0;
2274 goto err_create_pkt;
2275 }
2276
2277 pkt = (struct hfi_cmd_session_set_buffers_packet *)packet;
2278
2279 rc = call_hfi_pkt_op(device, session_set_buffers,
2280 pkt, session, buffer_info);
2281 if (rc) {
2282 dprintk(VIDC_ERR, "set buffers: failed to create packet\n");
2283 goto err_create_pkt;
2284 }
2285
2286 dprintk(VIDC_INFO, "set buffers: %#x\n", buffer_info->buffer_type);
2287 if (__iface_cmdq_write(session->device, pkt))
2288 rc = -ENOTEMPTY;
2289
2290err_create_pkt:
2291 mutex_unlock(&device->lock);
2292 return rc;
2293}
2294
2295static int venus_hfi_session_release_buffers(void *sess,
2296 struct vidc_buffer_addr_info *buffer_info)
2297{
2298 struct hfi_cmd_session_release_buffer_packet *pkt;
2299 u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE];
2300 int rc = 0;
2301 struct hal_session *session = sess;
2302 struct venus_hfi_device *device;
2303
2304 if (!session || !session->device || !buffer_info) {
2305 dprintk(VIDC_ERR, "Invalid Params\n");
2306 return -EINVAL;
2307 }
2308
2309 device = session->device;
2310 mutex_lock(&device->lock);
2311
2312 if (buffer_info->buffer_type == HAL_BUFFER_INPUT) {
2313 rc = 0;
2314 goto err_create_pkt;
2315 }
2316
2317 pkt = (struct hfi_cmd_session_release_buffer_packet *) packet;
2318
2319 rc = call_hfi_pkt_op(device, session_release_buffers,
2320 pkt, session, buffer_info);
2321 if (rc) {
2322 dprintk(VIDC_ERR, "release buffers: failed to create packet\n");
2323 goto err_create_pkt;
2324 }
2325
2326 dprintk(VIDC_INFO, "Release buffers: %#x\n", buffer_info->buffer_type);
2327 if (__iface_cmdq_write(session->device, pkt))
2328 rc = -ENOTEMPTY;
2329
2330err_create_pkt:
2331 mutex_unlock(&device->lock);
2332 return rc;
2333}
2334
2335static int venus_hfi_session_load_res(void *session)
2336{
2337 struct hal_session *sess;
2338 struct venus_hfi_device *device;
2339 int rc = 0;
2340
2341 if (!session) {
2342 dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
2343 return -EINVAL;
2344 }
2345
2346 sess = session;
2347 device = sess->device;
2348
2349 mutex_lock(&device->lock);
2350 rc = __send_session_cmd(sess, HFI_CMD_SESSION_LOAD_RESOURCES);
2351 mutex_unlock(&device->lock);
2352
2353 return rc;
2354}
2355
2356static int venus_hfi_session_release_res(void *session)
2357{
2358 struct hal_session *sess;
2359 struct venus_hfi_device *device;
2360 int rc = 0;
2361
2362 if (!session) {
2363 dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
2364 return -EINVAL;
2365 }
2366
2367 sess = session;
2368 device = sess->device;
2369
2370 mutex_lock(&device->lock);
2371 rc = __send_session_cmd(sess, HFI_CMD_SESSION_RELEASE_RESOURCES);
2372 mutex_unlock(&device->lock);
2373
2374 return rc;
2375}
2376
2377static int venus_hfi_session_start(void *session)
2378{
2379 struct hal_session *sess;
2380 struct venus_hfi_device *device;
2381 int rc = 0;
2382
2383 if (!session) {
2384 dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
2385 return -EINVAL;
2386 }
2387
2388 sess = session;
2389 device = sess->device;
2390
2391 mutex_lock(&device->lock);
2392 rc = __send_session_cmd(sess, HFI_CMD_SESSION_START);
2393 mutex_unlock(&device->lock);
2394
2395 return rc;
2396}
2397
2398static int venus_hfi_session_continue(void *session)
2399{
2400 struct hal_session *sess;
2401 struct venus_hfi_device *device;
2402 int rc = 0;
2403
2404 if (!session) {
2405 dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
2406 return -EINVAL;
2407 }
2408
2409 sess = session;
2410 device = sess->device;
2411
2412 mutex_lock(&device->lock);
2413 rc = __send_session_cmd(sess, HFI_CMD_SESSION_CONTINUE);
2414 mutex_unlock(&device->lock);
2415
2416 return rc;
2417}
2418
2419static int venus_hfi_session_stop(void *session)
2420{
2421 struct hal_session *sess;
2422 struct venus_hfi_device *device;
2423 int rc = 0;
2424
2425 if (!session) {
2426 dprintk(VIDC_ERR, "Invalid Params %s\n", __func__);
2427 return -EINVAL;
2428 }
2429
2430 sess = session;
2431 device = sess->device;
2432
2433 mutex_lock(&device->lock);
2434 rc = __send_session_cmd(sess, HFI_CMD_SESSION_STOP);
2435 mutex_unlock(&device->lock);
2436
2437 return rc;
2438}
2439
2440static int __session_etb(struct hal_session *session,
2441 struct vidc_frame_data *input_frame, bool relaxed)
2442{
2443 int rc = 0;
2444 struct venus_hfi_device *device = session->device;
2445
2446 if (session->is_decoder) {
2447 struct hfi_cmd_session_empty_buffer_compressed_packet pkt;
2448
2449 rc = call_hfi_pkt_op(device, session_etb_decoder,
2450 &pkt, session, input_frame);
2451 if (rc) {
2452 dprintk(VIDC_ERR,
2453 "Session etb decoder: failed to create pkt\n");
2454 goto err_create_pkt;
2455 }
2456
2457 if (!relaxed)
2458 rc = __iface_cmdq_write(session->device, &pkt);
2459 else
2460 rc = __iface_cmdq_write_relaxed(session->device,
2461 &pkt, NULL);
2462 if (rc)
2463 goto err_create_pkt;
2464 } else {
2465 struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet
2466 pkt;
2467
2468 rc = call_hfi_pkt_op(device, session_etb_encoder,
2469 &pkt, session, input_frame);
2470 if (rc) {
2471 dprintk(VIDC_ERR,
2472 "Session etb encoder: failed to create pkt\n");
2473 goto err_create_pkt;
2474 }
2475
2476 if (!relaxed)
2477 rc = __iface_cmdq_write(session->device, &pkt);
2478 else
2479 rc = __iface_cmdq_write_relaxed(session->device,
2480 &pkt, NULL);
2481 if (rc)
2482 goto err_create_pkt;
2483 }
2484
2485err_create_pkt:
2486 return rc;
2487}
2488
2489static int venus_hfi_session_etb(void *sess,
2490 struct vidc_frame_data *input_frame)
2491{
2492 int rc = 0;
2493 struct hal_session *session = sess;
2494 struct venus_hfi_device *device;
2495
2496 if (!session || !session->device || !input_frame) {
2497 dprintk(VIDC_ERR, "Invalid Params\n");
2498 return -EINVAL;
2499 }
2500
2501 device = session->device;
2502 mutex_lock(&device->lock);
2503 rc = __session_etb(session, input_frame, false);
2504 mutex_unlock(&device->lock);
2505 return rc;
2506}
2507
2508static int __session_ftb(struct hal_session *session,
2509 struct vidc_frame_data *output_frame, bool relaxed)
2510{
2511 int rc = 0;
2512 struct venus_hfi_device *device = session->device;
2513 struct hfi_cmd_session_fill_buffer_packet pkt;
2514
2515 rc = call_hfi_pkt_op(device, session_ftb,
2516 &pkt, session, output_frame);
2517 if (rc) {
2518 dprintk(VIDC_ERR, "Session ftb: failed to create pkt\n");
2519 goto err_create_pkt;
2520 }
2521
2522 if (!relaxed)
2523 rc = __iface_cmdq_write(session->device, &pkt);
2524 else
2525 rc = __iface_cmdq_write_relaxed(session->device,
2526 &pkt, NULL);
2527
2528err_create_pkt:
2529 return rc;
2530}
2531
2532static int venus_hfi_session_ftb(void *sess,
2533 struct vidc_frame_data *output_frame)
2534{
2535 int rc = 0;
2536 struct hal_session *session = sess;
2537 struct venus_hfi_device *device;
2538
2539 if (!session || !session->device || !output_frame) {
2540 dprintk(VIDC_ERR, "Invalid Params\n");
2541 return -EINVAL;
2542 }
2543
2544 device = session->device;
2545 mutex_lock(&device->lock);
2546 rc = __session_ftb(session, output_frame, false);
2547 mutex_unlock(&device->lock);
2548 return rc;
2549}
2550
2551static int venus_hfi_session_process_batch(void *sess,
2552 int num_etbs, struct vidc_frame_data etbs[],
2553 int num_ftbs, struct vidc_frame_data ftbs[])
2554{
2555 int rc = 0, c = 0;
2556 struct hal_session *session = sess;
2557 struct venus_hfi_device *device;
2558 struct hfi_cmd_session_sync_process_packet pkt;
2559
2560 if (!session || !session->device) {
2561 dprintk(VIDC_ERR, "%s: Invalid Params\n", __func__);
2562 return -EINVAL;
2563 }
2564
2565 device = session->device;
2566
2567 mutex_lock(&device->lock);
2568 for (c = 0; c < num_ftbs; ++c) {
2569 rc = __session_ftb(session, &ftbs[c], true);
2570 if (rc) {
2571 dprintk(VIDC_ERR, "Failed to queue batched ftb: %d\n",
2572 rc);
2573 goto err_etbs_and_ftbs;
2574 }
2575 }
2576
2577 for (c = 0; c < num_etbs; ++c) {
2578 rc = __session_etb(session, &etbs[c], true);
2579 if (rc) {
2580 dprintk(VIDC_ERR, "Failed to queue batched etb: %d\n",
2581 rc);
2582 goto err_etbs_and_ftbs;
2583 }
2584 }
2585
2586 rc = call_hfi_pkt_op(device, session_sync_process, &pkt, session);
2587 if (rc) {
2588 dprintk(VIDC_ERR, "Failed to create sync packet\n");
2589 goto err_etbs_and_ftbs;
2590 }
2591
2592 if (__iface_cmdq_write(session->device, &pkt))
2593 rc = -ENOTEMPTY;
2594
2595err_etbs_and_ftbs:
2596 mutex_unlock(&device->lock);
2597 return rc;
2598}
2599
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08002600static int venus_hfi_session_get_buf_req(void *sess)
2601{
2602 struct hfi_cmd_session_get_property_packet pkt;
2603 int rc = 0;
2604 struct hal_session *session = sess;
2605 struct venus_hfi_device *device;
2606
2607 if (!session || !session->device) {
2608 dprintk(VIDC_ERR, "invalid session");
2609 return -ENODEV;
2610 }
2611
2612 device = session->device;
2613 mutex_lock(&device->lock);
2614
2615 rc = call_hfi_pkt_op(device, session_get_buf_req,
2616 &pkt, session);
2617 if (rc) {
2618 dprintk(VIDC_ERR,
2619 "Session get buf req: failed to create pkt\n");
2620 goto err_create_pkt;
2621 }
2622
2623 if (__iface_cmdq_write(session->device, &pkt))
2624 rc = -ENOTEMPTY;
2625err_create_pkt:
2626 mutex_unlock(&device->lock);
2627 return rc;
2628}
2629
2630static int venus_hfi_session_flush(void *sess, enum hal_flush flush_mode)
2631{
2632 struct hfi_cmd_session_flush_packet pkt;
2633 int rc = 0;
2634 struct hal_session *session = sess;
2635 struct venus_hfi_device *device;
2636
2637 if (!session || !session->device) {
2638 dprintk(VIDC_ERR, "invalid session");
2639 return -ENODEV;
2640 }
2641
2642 device = session->device;
2643 mutex_lock(&device->lock);
2644
2645 rc = call_hfi_pkt_op(device, session_flush,
2646 &pkt, session, flush_mode);
2647 if (rc) {
2648 dprintk(VIDC_ERR, "Session flush: failed to create pkt\n");
2649 goto err_create_pkt;
2650 }
2651
2652 if (__iface_cmdq_write(session->device, &pkt))
2653 rc = -ENOTEMPTY;
2654err_create_pkt:
2655 mutex_unlock(&device->lock);
2656 return rc;
2657}
2658
2659static int __check_core_registered(struct hal_device_data core,
2660 phys_addr_t fw_addr, u8 *reg_addr, u32 reg_size,
2661 phys_addr_t irq)
2662{
2663 struct venus_hfi_device *device;
2664 struct list_head *curr, *next;
2665
2666 if (core.dev_count) {
2667 list_for_each_safe(curr, next, &core.dev_head) {
2668 device = list_entry(curr,
2669 struct venus_hfi_device, list);
2670 if (device && device->hal_data->irq == irq &&
2671 (CONTAINS(device->hal_data->
2672 firmware_base,
2673 FIRMWARE_SIZE, fw_addr) ||
2674 CONTAINS(fw_addr, FIRMWARE_SIZE,
2675 device->hal_data->
2676 firmware_base) ||
2677 CONTAINS(device->hal_data->
2678 register_base,
2679 reg_size, reg_addr) ||
2680 CONTAINS(reg_addr, reg_size,
2681 device->hal_data->
2682 register_base) ||
2683 OVERLAPS(device->hal_data->
2684 register_base,
2685 reg_size, reg_addr, reg_size) ||
2686 OVERLAPS(reg_addr, reg_size,
2687 device->hal_data->
2688 register_base, reg_size) ||
2689 OVERLAPS(device->hal_data->
2690 firmware_base,
2691 FIRMWARE_SIZE, fw_addr,
2692 FIRMWARE_SIZE) ||
2693 OVERLAPS(fw_addr, FIRMWARE_SIZE,
2694 device->hal_data->
2695 firmware_base,
2696 FIRMWARE_SIZE))) {
2697 return 0;
2698 }
2699
2700 dprintk(VIDC_INFO, "Device not registered\n");
2701 return -EINVAL;
2702 }
2703 } else {
2704 dprintk(VIDC_INFO, "no device Registered\n");
2705 }
2706
2707 return -EINVAL;
2708}
2709
2710static void __process_fatal_error(
2711 struct venus_hfi_device *device)
2712{
2713 struct msm_vidc_cb_cmd_done cmd_done = {0};
2714
2715 cmd_done.device_id = device->device_id;
2716 device->callback(HAL_SYS_ERROR, &cmd_done);
2717}
2718
2719static int __prepare_pc(struct venus_hfi_device *device)
2720{
2721 int rc = 0;
2722 struct hfi_cmd_sys_pc_prep_packet pkt;
2723
2724 rc = call_hfi_pkt_op(device, sys_pc_prep, &pkt);
2725 if (rc) {
2726 dprintk(VIDC_ERR, "Failed to create sys pc prep pkt\n");
2727 goto err_pc_prep;
2728 }
2729
2730 if (__iface_cmdq_write(device, &pkt))
2731 rc = -ENOTEMPTY;
2732 if (rc)
2733 dprintk(VIDC_ERR, "Failed to prepare venus for power off");
2734err_pc_prep:
2735 return rc;
2736}
2737
2738static void venus_hfi_pm_handler(struct work_struct *work)
2739{
2740 int rc = 0;
2741 u32 wfi_status = 0, idle_status = 0, pc_ready = 0;
2742 int count = 0;
Praneeth Paladuguf3a8e5f2016-12-14 11:04:17 -08002743 const int max_tries = 10;
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08002744 struct venus_hfi_device *device = list_first_entry(
2745 &hal_ctxt.dev_head, struct venus_hfi_device, list);
2746
2747 if (!device) {
2748 dprintk(VIDC_ERR, "%s: NULL device\n", __func__);
2749 return;
2750 }
2751
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -07002752 dprintk(VIDC_PROF,
2753 "Entering venus_hfi_pm_handler\n");
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08002754 /*
2755 * It is ok to check this variable outside the lock since
2756 * it is being updated in this context only
2757 */
2758 if (device->skip_pc_count >= VIDC_MAX_PC_SKIP_COUNT) {
2759 dprintk(VIDC_WARN, "Failed to PC for %d times\n",
2760 device->skip_pc_count);
2761 device->skip_pc_count = 0;
2762 __process_fatal_error(device);
2763 return;
2764 }
2765 mutex_lock(&device->lock);
2766 if (!device->power_enabled) {
2767 dprintk(VIDC_DBG, "%s: Power already disabled\n",
2768 __func__);
2769 goto exit;
2770 }
2771
2772 rc = __core_in_valid_state(device);
2773 if (!rc) {
2774 dprintk(VIDC_WARN,
2775 "Core is in bad state, Skipping power collapse\n");
2776 goto skip_power_off;
2777 }
2778 pc_ready = __read_register(device, VIDC_CPU_CS_SCIACMDARG0) &
2779 VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY;
2780 if (!pc_ready) {
2781 wfi_status = __read_register(device,
2782 VIDC_WRAPPER_CPU_STATUS);
2783 idle_status = __read_register(device,
2784 VIDC_CPU_CS_SCIACMDARG0);
Maheshwar Ajja79c2eb82017-04-14 12:23:34 -07002785 if (!(wfi_status & BIT(0))) {
2786 dprintk(VIDC_WARN,
2787 "Skipping PC as wfi_status (%#x) bit not set\n",
2788 wfi_status);
2789 goto skip_power_off;
2790 }
2791 if (device->res->sys_idle_indicator &&
2792 !(idle_status & BIT(30))) {
2793 dprintk(VIDC_WARN,
2794 "Skipping PC as idle_status (%#x) bit not set\n",
2795 idle_status);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08002796 goto skip_power_off;
2797 }
2798
2799 rc = __prepare_pc(device);
2800 if (rc) {
2801 dprintk(VIDC_WARN, "Failed PC %d\n", rc);
2802 goto skip_power_off;
2803 }
2804
2805 while (count < max_tries) {
2806 wfi_status = __read_register(device,
2807 VIDC_WRAPPER_CPU_STATUS);
2808 pc_ready = __read_register(device,
2809 VIDC_CPU_CS_SCIACMDARG0);
2810 if ((wfi_status & BIT(0)) && (pc_ready &
2811 VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY))
2812 break;
Praneeth Paladuguf3a8e5f2016-12-14 11:04:17 -08002813 usleep_range(150, 250);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08002814 count++;
2815 }
2816
2817 if (count == max_tries) {
2818 dprintk(VIDC_ERR,
2819 "Skip PC. Core is not in right state (%#x, %#x)\n",
2820 wfi_status, pc_ready);
2821 goto skip_power_off;
2822 }
2823 }
2824
2825 rc = __suspend(device);
2826 if (rc)
2827 dprintk(VIDC_ERR, "Failed venus power off\n");
2828
2829 /* Cancel pending delayed works if any */
2830 cancel_delayed_work(&venus_hfi_pm_work);
2831 device->skip_pc_count = 0;
2832
2833 mutex_unlock(&device->lock);
2834 return;
2835
2836skip_power_off:
2837 device->skip_pc_count++;
2838 dprintk(VIDC_WARN, "Skip PC(%d, %#x, %#x, %#x)\n",
2839 device->skip_pc_count, wfi_status, idle_status, pc_ready);
2840 queue_delayed_work(device->venus_pm_workq,
2841 &venus_hfi_pm_work,
2842 msecs_to_jiffies(msm_vidc_pwr_collapse_delay));
2843exit:
2844 mutex_unlock(&device->lock);
2845}
2846
2847static void __process_sys_error(struct venus_hfi_device *device)
2848{
2849 struct hfi_sfr_struct *vsfr = NULL;
2850
2851 __set_state(device, VENUS_STATE_DEINIT);
2852
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08002853 vsfr = (struct hfi_sfr_struct *)device->sfr.align_virtual_addr;
2854 if (vsfr) {
2855 void *p = memchr(vsfr->rg_data, '\0', vsfr->bufSize);
2856 /*
2857 * SFR isn't guaranteed to be NULL terminated
2858 * since SYS_ERROR indicates that Venus is in the
2859 * process of crashing.
2860 */
2861 if (p == NULL)
2862 vsfr->rg_data[vsfr->bufSize - 1] = '\0';
2863
2864 dprintk(VIDC_ERR, "SFR Message from FW: %s\n",
2865 vsfr->rg_data);
2866 }
2867}
2868
2869static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet)
2870{
2871 bool local_packet = false;
2872 enum vidc_msg_prio log_level = VIDC_FW;
2873
2874 if (!device) {
2875 dprintk(VIDC_ERR, "%s: Invalid params\n", __func__);
2876 return;
2877 }
2878
2879 if (!packet) {
2880 packet = kzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE, GFP_TEMPORARY);
2881 if (!packet) {
2882 dprintk(VIDC_ERR, "In %s() Fail to allocate mem\n",
2883 __func__);
2884 return;
2885 }
2886
2887 local_packet = true;
2888
2889 /*
2890 * Local packek is used when something FATAL occurred.
2891 * It is good to print these logs by default.
2892 */
2893
2894 log_level = VIDC_ERR;
2895 }
2896
2897 while (!__iface_dbgq_read(device, packet)) {
2898 struct hfi_msg_sys_coverage_packet *pkt =
2899 (struct hfi_msg_sys_coverage_packet *) packet;
2900
2901 if (pkt->packet_type == HFI_MSG_SYS_COV) {
2902 int stm_size = 0;
2903
2904 stm_size = stm_log_inv_ts(0, 0,
2905 pkt->rg_msg_data, pkt->msg_size);
2906 if (stm_size == 0)
2907 dprintk(VIDC_ERR,
2908 "In %s, stm_log returned size of 0\n",
2909 __func__);
2910 } else {
2911 struct hfi_msg_sys_debug_packet *pkt =
2912 (struct hfi_msg_sys_debug_packet *) packet;
2913 dprintk(log_level, "%s", pkt->rg_msg_data);
2914 }
2915 }
2916
2917 if (local_packet)
2918 kfree(packet);
2919}
2920
2921static struct hal_session *__get_session(struct venus_hfi_device *device,
2922 u32 session_id)
2923{
2924 struct hal_session *temp = NULL;
2925
2926 list_for_each_entry(temp, &device->sess_head, list) {
2927 if (session_id == hash32_ptr(temp))
2928 return temp;
2929 }
2930
2931 return NULL;
2932}
2933
2934static int __response_handler(struct venus_hfi_device *device)
2935{
2936 struct msm_vidc_cb_info *packets;
2937 int packet_count = 0;
2938 u8 *raw_packet = NULL;
2939 bool requeue_pm_work = true;
2940
2941 if (!device || device->state != VENUS_STATE_INIT)
2942 return 0;
2943
2944 packets = device->response_pkt;
2945
2946 raw_packet = device->raw_packet;
2947
2948 if (!raw_packet || !packets) {
2949 dprintk(VIDC_ERR,
2950 "%s: Invalid args : Res packet = %p, Raw packet = %p\n",
2951 __func__, packets, raw_packet);
2952 return 0;
2953 }
2954
2955 if (device->intr_status & VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK) {
2956 struct hfi_sfr_struct *vsfr = (struct hfi_sfr_struct *)
2957 device->sfr.align_virtual_addr;
2958 struct msm_vidc_cb_info info = {
2959 .response_type = HAL_SYS_WATCHDOG_TIMEOUT,
2960 .response.cmd = {
2961 .device_id = device->device_id,
2962 }
2963 };
2964
2965 if (vsfr)
2966 dprintk(VIDC_ERR, "SFR Message from FW: %s\n",
2967 vsfr->rg_data);
2968
2969 dprintk(VIDC_ERR, "Received watchdog timeout\n");
2970 packets[packet_count++] = info;
2971 goto exit;
2972 }
2973
2974 /* Bleed the msg queue dry of packets */
2975 while (!__iface_msgq_read(device, raw_packet)) {
2976 void **session_id = NULL;
2977 struct msm_vidc_cb_info *info = &packets[packet_count++];
2978 struct vidc_hal_sys_init_done sys_init_done = {0};
2979 int rc = 0;
2980
2981 rc = hfi_process_msg_packet(device->device_id,
2982 (struct vidc_hal_msg_pkt_hdr *)raw_packet, info);
2983 if (rc) {
2984 dprintk(VIDC_WARN,
2985 "Corrupt/unknown packet found, discarding\n");
2986 --packet_count;
2987 continue;
2988 }
2989
2990 /* Process the packet types that we're interested in */
2991 switch (info->response_type) {
2992 case HAL_SYS_ERROR:
2993 __process_sys_error(device);
2994 break;
2995 case HAL_SYS_RELEASE_RESOURCE_DONE:
2996 dprintk(VIDC_DBG, "Received SYS_RELEASE_RESOURCE\n");
2997 break;
2998 case HAL_SYS_INIT_DONE:
2999 dprintk(VIDC_DBG, "Received SYS_INIT_DONE\n");
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -07003000
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003001 sys_init_done.capabilities =
3002 device->sys_init_capabilities;
3003 hfi_process_sys_init_done_prop_read(
3004 (struct hfi_msg_sys_init_done_packet *)
3005 raw_packet, &sys_init_done);
3006 info->response.cmd.data.sys_init_done = sys_init_done;
3007 break;
3008 case HAL_SESSION_LOAD_RESOURCE_DONE:
3009 /*
3010 * Work around for H/W bug, need to re-program these
3011 * registers as part of a handshake agreement with the
3012 * firmware. This strictly only needs to be done for
3013 * decoder secure sessions, but there's no harm in doing
3014 * so for all sessions as it's at worst a NO-OP.
3015 */
3016 __set_threshold_registers(device);
3017 break;
3018 default:
3019 break;
3020 }
3021
3022 /* For session-related packets, validate session */
3023 switch (info->response_type) {
3024 case HAL_SESSION_LOAD_RESOURCE_DONE:
3025 case HAL_SESSION_INIT_DONE:
3026 case HAL_SESSION_END_DONE:
3027 case HAL_SESSION_ABORT_DONE:
3028 case HAL_SESSION_START_DONE:
3029 case HAL_SESSION_STOP_DONE:
3030 case HAL_SESSION_FLUSH_DONE:
3031 case HAL_SESSION_SUSPEND_DONE:
3032 case HAL_SESSION_RESUME_DONE:
3033 case HAL_SESSION_SET_PROP_DONE:
3034 case HAL_SESSION_GET_PROP_DONE:
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003035 case HAL_SESSION_RELEASE_BUFFER_DONE:
3036 case HAL_SESSION_RELEASE_RESOURCE_DONE:
3037 case HAL_SESSION_PROPERTY_INFO:
3038 session_id = &info->response.cmd.session_id;
3039 break;
3040 case HAL_SESSION_ERROR:
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003041 case HAL_SESSION_ETB_DONE:
3042 case HAL_SESSION_FTB_DONE:
3043 session_id = &info->response.data.session_id;
3044 break;
3045 case HAL_SESSION_EVENT_CHANGE:
3046 session_id = &info->response.event.session_id;
3047 break;
3048 case HAL_RESPONSE_UNUSED:
3049 default:
3050 session_id = NULL;
3051 break;
3052 }
3053
3054 /*
3055 * hfi_process_msg_packet provides a session_id that's a hashed
3056 * value of struct hal_session, we need to coerce the hashed
3057 * value back to pointer that we can use. Ideally, hfi_process\
3058 * _msg_packet should take care of this, but it doesn't have
3059 * required information for it
3060 */
3061 if (session_id) {
3062 struct hal_session *session = NULL;
3063
3064 WARN_ON(upper_32_bits((uintptr_t)*session_id) != 0);
3065 session = __get_session(device,
3066 (u32)(uintptr_t)*session_id);
3067 if (!session) {
3068 dprintk(VIDC_ERR,
3069 "Received a packet (%#x) for an unrecognized session (%pK), discarding\n",
3070 info->response_type,
3071 *session_id);
3072 --packet_count;
3073 continue;
3074 }
3075
3076 *session_id = session->session_id;
3077 }
3078
3079 if (packet_count >= max_packets &&
3080 __get_q_size(device, VIDC_IFACEQ_MSGQ_IDX)) {
3081 dprintk(VIDC_WARN,
3082 "Too many packets in message queue to handle at once, deferring read\n");
3083 break;
3084 }
3085 }
3086
3087 if (requeue_pm_work && device->res->sw_power_collapsible) {
3088 cancel_delayed_work(&venus_hfi_pm_work);
3089 if (!queue_delayed_work(device->venus_pm_workq,
3090 &venus_hfi_pm_work,
3091 msecs_to_jiffies(msm_vidc_pwr_collapse_delay))) {
3092 dprintk(VIDC_ERR, "PM work already scheduled\n");
3093 }
3094 }
3095
3096exit:
3097 __flush_debug_queue(device, raw_packet);
3098
3099 return packet_count;
3100}
3101
3102static void venus_hfi_core_work_handler(struct work_struct *work)
3103{
3104 struct venus_hfi_device *device = list_first_entry(
3105 &hal_ctxt.dev_head, struct venus_hfi_device, list);
3106 int num_responses = 0, i = 0;
3107 u32 intr_status;
3108
3109 mutex_lock(&device->lock);
3110
3111 dprintk(VIDC_INFO, "Handling interrupt\n");
3112
3113 if (!__core_in_valid_state(device)) {
3114 dprintk(VIDC_DBG, "%s - Core not in init state\n", __func__);
3115 goto err_no_work;
3116 }
3117
3118 if (!device->callback) {
3119 dprintk(VIDC_ERR, "No interrupt callback function: %pK\n",
3120 device);
3121 goto err_no_work;
3122 }
3123
3124 if (__resume(device)) {
3125 dprintk(VIDC_ERR, "%s: Power enable failed\n", __func__);
3126 goto err_no_work;
3127 }
3128
3129 __core_clear_interrupt(device);
3130 num_responses = __response_handler(device);
3131
3132err_no_work:
3133
3134 /* Keep the interrupt status before releasing device lock */
3135 intr_status = device->intr_status;
3136 mutex_unlock(&device->lock);
3137
3138 /*
3139 * Issue the callbacks outside of the locked contex to preserve
3140 * re-entrancy.
3141 */
3142
3143 for (i = 0; !IS_ERR_OR_NULL(device->response_pkt) &&
3144 i < num_responses; ++i) {
3145 struct msm_vidc_cb_info *r = &device->response_pkt[i];
3146
3147 device->callback(r->response_type, &r->response);
3148 }
3149
3150 /* We need re-enable the irq which was disabled in ISR handler */
3151 if (!(intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
3152 enable_irq(device->hal_data->irq);
3153
3154 /*
3155 * XXX: Don't add any code beyond here. Reacquiring locks after release
3156 * it above doesn't guarantee the atomicity that we're aiming for.
3157 */
3158}
3159
3160static DECLARE_WORK(venus_hfi_work, venus_hfi_core_work_handler);
3161
3162static irqreturn_t venus_hfi_isr(int irq, void *dev)
3163{
3164 struct venus_hfi_device *device = dev;
3165
3166 dprintk(VIDC_INFO, "Received an interrupt %d\n", irq);
3167 disable_irq_nosync(irq);
3168 queue_work(device->vidc_workq, &venus_hfi_work);
3169 return IRQ_HANDLED;
3170}
3171
3172static int __init_regs_and_interrupts(struct venus_hfi_device *device,
3173 struct msm_vidc_platform_resources *res)
3174{
3175 struct hal_data *hal = NULL;
3176 int rc = 0;
3177
3178 rc = __check_core_registered(hal_ctxt, res->firmware_base,
3179 (u8 *)(uintptr_t)res->register_base,
3180 res->register_size, res->irq);
3181 if (!rc) {
3182 dprintk(VIDC_ERR, "Core present/Already added\n");
3183 rc = -EEXIST;
3184 goto err_core_init;
3185 }
3186
3187 dprintk(VIDC_DBG, "HAL_DATA will be assigned now\n");
3188 hal = (struct hal_data *)
3189 kzalloc(sizeof(struct hal_data), GFP_KERNEL);
3190 if (!hal) {
3191 dprintk(VIDC_ERR, "Failed to alloc\n");
3192 rc = -ENOMEM;
3193 goto err_core_init;
3194 }
3195
3196 hal->irq = res->irq;
3197 hal->firmware_base = res->firmware_base;
3198 hal->register_base = devm_ioremap_nocache(&res->pdev->dev,
3199 res->register_base, res->register_size);
3200 hal->register_size = res->register_size;
3201 if (!hal->register_base) {
3202 dprintk(VIDC_ERR,
3203 "could not map reg addr %pa of size %d\n",
3204 &res->register_base, res->register_size);
3205 goto error_irq_fail;
3206 }
3207
3208 device->hal_data = hal;
3209 rc = request_irq(res->irq, venus_hfi_isr, IRQF_TRIGGER_HIGH,
3210 "msm_vidc", device);
3211 if (unlikely(rc)) {
3212 dprintk(VIDC_ERR, "() :request_irq failed\n");
3213 goto error_irq_fail;
3214 }
3215
3216 disable_irq_nosync(res->irq);
3217 dprintk(VIDC_INFO,
3218 "firmware_base = %pa, register_base = %pa, register_size = %d\n",
3219 &res->firmware_base, &res->register_base,
3220 res->register_size);
3221 return rc;
3222
3223error_irq_fail:
3224 kfree(hal);
3225err_core_init:
3226 return rc;
3227
3228}
3229
3230static inline void __deinit_clocks(struct venus_hfi_device *device)
3231{
3232 struct clock_info *cl;
3233
3234 device->clk_freq = 0;
3235 venus_hfi_for_each_clock_reverse(device, cl) {
3236 if (cl->clk) {
3237 clk_put(cl->clk);
3238 cl->clk = NULL;
3239 }
3240 }
3241}
3242
3243static inline int __init_clocks(struct venus_hfi_device *device)
3244{
3245 int rc = 0;
3246 struct clock_info *cl = NULL;
3247
3248 if (!device) {
3249 dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
3250 return -EINVAL;
3251 }
3252
3253 venus_hfi_for_each_clock(device, cl) {
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003254
3255 dprintk(VIDC_DBG, "%s: scalable? %d, count %d\n",
3256 cl->name, cl->has_scaling, cl->count);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003257 }
3258
3259 venus_hfi_for_each_clock(device, cl) {
3260 if (!cl->clk) {
3261 cl->clk = clk_get(&device->res->pdev->dev, cl->name);
3262 if (IS_ERR_OR_NULL(cl->clk)) {
3263 dprintk(VIDC_ERR,
3264 "Failed to get clock: %s\n", cl->name);
3265 rc = PTR_ERR(cl->clk) ?: -EINVAL;
3266 cl->clk = NULL;
3267 goto err_clk_get;
3268 }
3269 }
3270 }
3271 device->clk_freq = 0;
3272 return 0;
3273
3274err_clk_get:
3275 __deinit_clocks(device);
3276 return rc;
3277}
3278
3279
3280static inline void __disable_unprepare_clks(struct venus_hfi_device *device)
3281{
3282 struct clock_info *cl;
Praneeth Paladugu03edb082017-04-17 10:31:14 -07003283 int rc = 0;
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003284
3285 if (!device) {
3286 dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
3287 return;
3288 }
3289
3290 venus_hfi_for_each_clock_reverse(device, cl) {
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003291 dprintk(VIDC_DBG, "Clock: %s disable and unprepare\n",
3292 cl->name);
Praneeth Paladugu03edb082017-04-17 10:31:14 -07003293 rc = clk_set_flags(cl->clk, CLKFLAG_NORETAIN_PERIPH);
3294 if (rc) {
3295 dprintk(VIDC_WARN,
3296 "Failed set flag NORETAIN_PERIPH %s\n",
3297 cl->name);
3298 }
3299 rc = clk_set_flags(cl->clk, CLKFLAG_NORETAIN_MEM);
3300 if (rc) {
3301 dprintk(VIDC_WARN,
3302 "Failed set flag NORETAIN_MEM %s\n",
3303 cl->name);
3304 }
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003305 clk_disable_unprepare(cl->clk);
3306 }
3307}
3308
3309static inline int __prepare_enable_clks(struct venus_hfi_device *device)
3310{
3311 struct clock_info *cl = NULL, *cl_fail = NULL;
3312 int rc = 0, c = 0;
3313
3314 if (!device) {
3315 dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
3316 return -EINVAL;
3317 }
3318
3319 venus_hfi_for_each_clock(device, cl) {
3320 /*
3321 * For the clocks we control, set the rate prior to preparing
3322 * them. Since we don't really have a load at this point, scale
3323 * it to the lowest frequency possible
3324 */
3325 if (cl->has_scaling)
3326 clk_set_rate(cl->clk, clk_round_rate(cl->clk, 0));
3327
Praneeth Paladugu03edb082017-04-17 10:31:14 -07003328 rc = clk_set_flags(cl->clk, CLKFLAG_RETAIN_PERIPH);
3329 if (rc) {
3330 dprintk(VIDC_WARN,
3331 "Failed set flag RETAIN_PERIPH %s\n",
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003332 cl->name);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003333 }
Praneeth Paladugu03edb082017-04-17 10:31:14 -07003334 rc = clk_set_flags(cl->clk, CLKFLAG_RETAIN_MEM);
3335 if (rc) {
3336 dprintk(VIDC_WARN,
3337 "Failed set flag RETAIN_MEM %s\n",
3338 cl->name);
3339 }
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003340 rc = clk_prepare_enable(cl->clk);
3341 if (rc) {
3342 dprintk(VIDC_ERR, "Failed to enable clocks\n");
3343 cl_fail = cl;
3344 goto fail_clk_enable;
3345 }
3346
3347 c++;
3348 dprintk(VIDC_DBG, "Clock: %s prepared and enabled\n", cl->name);
3349 }
3350
3351 __write_register(device, VIDC_WRAPPER_CLOCK_CONFIG, 0);
3352 __write_register(device, VIDC_WRAPPER_CPU_CLOCK_CONFIG, 0);
3353 return rc;
3354
3355fail_clk_enable:
3356 venus_hfi_for_each_clock_reverse_continue(device, cl, c) {
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003357 dprintk(VIDC_ERR, "Clock: %s disable and unprepare\n",
3358 cl->name);
3359 clk_disable_unprepare(cl->clk);
3360 }
3361
3362 return rc;
3363}
3364
3365static void __deinit_bus(struct venus_hfi_device *device)
3366{
3367 struct bus_info *bus = NULL;
3368
3369 if (!device)
3370 return;
3371
3372 kfree(device->bus_vote.data);
3373 device->bus_vote = DEFAULT_BUS_VOTE;
3374
3375 venus_hfi_for_each_bus_reverse(device, bus) {
3376 devfreq_remove_device(bus->devfreq);
3377 bus->devfreq = NULL;
3378 dev_set_drvdata(bus->dev, NULL);
3379
3380 msm_bus_scale_unregister(bus->client);
3381 bus->client = NULL;
3382 }
3383}
3384
3385static int __init_bus(struct venus_hfi_device *device)
3386{
3387 struct bus_info *bus = NULL;
3388 int rc = 0;
3389
3390 if (!device)
3391 return -EINVAL;
3392
3393 venus_hfi_for_each_bus(device, bus) {
3394 struct devfreq_dev_profile profile = {
3395 .initial_freq = 0,
3396 .polling_ms = INT_MAX,
3397 .freq_table = NULL,
3398 .max_state = 0,
3399 .target = __devfreq_target,
3400 .get_dev_status = __devfreq_get_status,
3401 .exit = NULL,
3402 };
3403
3404 /*
3405 * This is stupid, but there's no other easy way to ahold
3406 * of struct bus_info in venus_hfi_devfreq_*()
3407 */
3408 WARN(dev_get_drvdata(bus->dev), "%s's drvdata already set\n",
3409 dev_name(bus->dev));
3410 dev_set_drvdata(bus->dev, device);
3411
3412 bus->client = msm_bus_scale_register(bus->master, bus->slave,
3413 bus->name, false);
3414 if (IS_ERR_OR_NULL(bus->client)) {
3415 rc = PTR_ERR(bus->client) ?: -EBADHANDLE;
3416 dprintk(VIDC_ERR, "Failed to register bus %s: %d\n",
3417 bus->name, rc);
3418 bus->client = NULL;
3419 goto err_add_dev;
3420 }
3421
3422 bus->devfreq_prof = profile;
3423 bus->devfreq = devfreq_add_device(bus->dev,
3424 &bus->devfreq_prof, bus->governor, NULL);
3425 if (IS_ERR_OR_NULL(bus->devfreq)) {
3426 rc = PTR_ERR(bus->devfreq) ?: -EBADHANDLE;
3427 dprintk(VIDC_ERR,
3428 "Failed to add devfreq device for bus %s and governor %s: %d\n",
3429 bus->name, bus->governor, rc);
3430 bus->devfreq = NULL;
3431 goto err_add_dev;
3432 }
3433
3434 /*
3435 * Devfreq starts monitoring immediately, since we are just
3436 * initializing stuff at this point, force it to suspend
3437 */
3438 devfreq_suspend_device(bus->devfreq);
3439 }
3440
3441 device->bus_vote = DEFAULT_BUS_VOTE;
3442 return 0;
3443
3444err_add_dev:
3445 __deinit_bus(device);
3446 return rc;
3447}
3448
3449static void __deinit_regulators(struct venus_hfi_device *device)
3450{
3451 struct regulator_info *rinfo = NULL;
3452
3453 venus_hfi_for_each_regulator_reverse(device, rinfo) {
3454 if (rinfo->regulator) {
3455 regulator_put(rinfo->regulator);
3456 rinfo->regulator = NULL;
3457 }
3458 }
3459}
3460
3461static int __init_regulators(struct venus_hfi_device *device)
3462{
3463 int rc = 0;
3464 struct regulator_info *rinfo = NULL;
3465
3466 venus_hfi_for_each_regulator(device, rinfo) {
3467 rinfo->regulator = regulator_get(&device->res->pdev->dev,
3468 rinfo->name);
3469 if (IS_ERR_OR_NULL(rinfo->regulator)) {
3470 rc = PTR_ERR(rinfo->regulator) ?: -EBADHANDLE;
3471 dprintk(VIDC_ERR, "Failed to get regulator: %s\n",
3472 rinfo->name);
3473 rinfo->regulator = NULL;
3474 goto err_reg_get;
3475 }
3476 }
3477
3478 return 0;
3479
3480err_reg_get:
3481 __deinit_regulators(device);
3482 return rc;
3483}
3484
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -07003485static void __deinit_subcaches(struct venus_hfi_device *device)
3486{
3487 struct subcache_info *sinfo = NULL;
3488
3489 if (!device) {
3490 dprintk(VIDC_ERR, "deinit_subcaches: invalid device %pK\n",
3491 device);
3492 goto exit;
3493 }
3494
3495 if (!device->res->sys_cache_enabled)
3496 goto exit;
3497
3498 venus_hfi_for_each_subcache_reverse(device, sinfo) {
3499 if (sinfo->subcache) {
3500 dprintk(VIDC_DBG, "deinit_subcaches: %s\n",
3501 sinfo->name);
3502 llcc_slice_putd(sinfo->subcache);
3503 sinfo->subcache = NULL;
3504 }
3505 }
3506
3507exit:
3508 return;
3509}
3510
3511static int __init_subcaches(struct venus_hfi_device *device)
3512{
3513 int rc = 0;
3514 struct subcache_info *sinfo = NULL;
3515
3516 if (!device) {
3517 dprintk(VIDC_ERR, "init_subcaches: invalid device %pK\n",
3518 device);
3519 return -EINVAL;
3520 }
3521
3522 if (!device->res->sys_cache_enabled)
3523 return 0;
3524
3525 venus_hfi_for_each_subcache(device, sinfo) {
3526 sinfo->subcache = llcc_slice_getd(&device->res->pdev->dev,
3527 sinfo->name);
3528 if (IS_ERR_OR_NULL(sinfo->subcache)) {
3529 rc = PTR_ERR(sinfo->subcache) ? : -EBADHANDLE;
3530 dprintk(VIDC_ERR,
3531 "init_subcaches: invalid subcache: %s rc %d\n",
3532 sinfo->name, rc);
3533 sinfo->subcache = NULL;
3534 goto err_subcache_get;
3535 }
3536 dprintk(VIDC_DBG, "init_subcaches: %s\n",
3537 sinfo->name);
3538 }
3539
3540 return 0;
3541
3542err_subcache_get:
3543 __deinit_subcaches(device);
3544 return rc;
3545}
3546
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003547static int __init_resources(struct venus_hfi_device *device,
3548 struct msm_vidc_platform_resources *res)
3549{
3550 int rc = 0;
3551
3552 rc = __init_regulators(device);
3553 if (rc) {
3554 dprintk(VIDC_ERR, "Failed to get all regulators\n");
3555 return -ENODEV;
3556 }
3557
3558 rc = __init_clocks(device);
3559 if (rc) {
3560 dprintk(VIDC_ERR, "Failed to init clocks\n");
3561 rc = -ENODEV;
3562 goto err_init_clocks;
3563 }
3564
3565 rc = __init_bus(device);
3566 if (rc) {
3567 dprintk(VIDC_ERR, "Failed to init bus: %d\n", rc);
3568 goto err_init_bus;
3569 }
3570
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -07003571 rc = __init_subcaches(device);
3572 if (rc)
3573 dprintk(VIDC_WARN, "Failed to init subcaches: %d\n", rc);
3574
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003575 device->sys_init_capabilities =
3576 kzalloc(sizeof(struct msm_vidc_capability)
3577 * VIDC_MAX_SESSIONS, GFP_TEMPORARY);
3578
3579 return rc;
3580
3581err_init_bus:
3582 __deinit_clocks(device);
3583err_init_clocks:
3584 __deinit_regulators(device);
3585 return rc;
3586}
3587
3588static void __deinit_resources(struct venus_hfi_device *device)
3589{
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -07003590 __deinit_subcaches(device);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003591 __deinit_bus(device);
3592 __deinit_clocks(device);
3593 __deinit_regulators(device);
3594 kfree(device->sys_init_capabilities);
3595 device->sys_init_capabilities = NULL;
3596}
3597
3598static int __protect_cp_mem(struct venus_hfi_device *device)
3599{
3600 struct tzbsp_memprot memprot;
3601 unsigned int resp = 0;
3602 int rc = 0;
3603 struct context_bank_info *cb;
3604 struct scm_desc desc = {0};
3605
3606 if (!device)
3607 return -EINVAL;
3608
3609 memprot.cp_start = 0x0;
3610 memprot.cp_size = 0x0;
3611 memprot.cp_nonpixel_start = 0x0;
3612 memprot.cp_nonpixel_size = 0x0;
3613
3614 list_for_each_entry(cb, &device->res->context_banks, list) {
3615 if (!strcmp(cb->name, "venus_ns")) {
3616 desc.args[1] = memprot.cp_size =
3617 cb->addr_range.start;
3618 dprintk(VIDC_DBG, "%s memprot.cp_size: %#x\n",
3619 __func__, memprot.cp_size);
3620 }
3621
3622 if (!strcmp(cb->name, "venus_sec_non_pixel")) {
3623 desc.args[2] = memprot.cp_nonpixel_start =
3624 cb->addr_range.start;
3625 desc.args[3] = memprot.cp_nonpixel_size =
3626 cb->addr_range.size;
3627 dprintk(VIDC_DBG,
3628 "%s memprot.cp_nonpixel_start: %#x size: %#x\n",
3629 __func__, memprot.cp_nonpixel_start,
3630 memprot.cp_nonpixel_size);
3631 }
3632 }
3633
3634 if (!is_scm_armv8()) {
3635 rc = scm_call(SCM_SVC_MP, TZBSP_MEM_PROTECT_VIDEO_VAR, &memprot,
3636 sizeof(memprot), &resp, sizeof(resp));
3637 } else {
3638 desc.arginfo = SCM_ARGS(4);
3639 rc = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
3640 TZBSP_MEM_PROTECT_VIDEO_VAR), &desc);
3641 resp = desc.ret[0];
3642 }
3643
3644 if (rc) {
3645 dprintk(VIDC_ERR, "Failed to protect memory(%d) response: %d\n",
3646 rc, resp);
3647 }
3648
3649 trace_venus_hfi_var_done(
3650 memprot.cp_start, memprot.cp_size,
3651 memprot.cp_nonpixel_start, memprot.cp_nonpixel_size);
3652 return rc;
3653}
3654
3655static int __disable_regulator(struct regulator_info *rinfo)
3656{
3657 int rc = 0;
3658
3659 dprintk(VIDC_DBG, "Disabling regulator %s\n", rinfo->name);
3660
3661 /*
3662 * This call is needed. Driver needs to acquire the control back
3663 * from HW in order to disable the regualtor. Else the behavior
3664 * is unknown.
3665 */
3666
3667 rc = __acquire_regulator(rinfo);
3668 if (rc) {
3669 /*
3670 * This is somewhat fatal, but nothing we can do
3671 * about it. We can't disable the regulator w/o
3672 * getting it back under s/w control
3673 */
3674 dprintk(VIDC_WARN,
3675 "Failed to acquire control on %s\n",
3676 rinfo->name);
3677
3678 goto disable_regulator_failed;
3679 }
3680
3681 rc = regulator_disable(rinfo->regulator);
3682 if (rc) {
3683 dprintk(VIDC_WARN,
3684 "Failed to disable %s: %d\n",
3685 rinfo->name, rc);
3686 goto disable_regulator_failed;
3687 }
3688
3689 return 0;
3690disable_regulator_failed:
3691
3692 /* Bring attention to this issue */
3693 WARN_ON(1);
3694 return rc;
3695}
3696
3697static int __enable_hw_power_collapse(struct venus_hfi_device *device)
3698{
3699 int rc = 0;
3700
3701 if (!msm_vidc_fw_low_power_mode) {
3702 dprintk(VIDC_DBG, "Not enabling hardware power collapse\n");
3703 return 0;
3704 }
3705
3706 rc = __hand_off_regulators(device);
3707 if (rc)
3708 dprintk(VIDC_WARN,
3709 "%s : Failed to enable HW power collapse %d\n",
3710 __func__, rc);
3711 return rc;
3712}
3713
3714static int __enable_regulators(struct venus_hfi_device *device)
3715{
3716 int rc = 0, c = 0;
3717 struct regulator_info *rinfo;
3718
3719 dprintk(VIDC_DBG, "Enabling regulators\n");
3720
3721 venus_hfi_for_each_regulator(device, rinfo) {
3722 rc = regulator_enable(rinfo->regulator);
3723 if (rc) {
3724 dprintk(VIDC_ERR,
3725 "Failed to enable %s: %d\n",
3726 rinfo->name, rc);
3727 goto err_reg_enable_failed;
3728 }
3729
3730 dprintk(VIDC_DBG, "Enabled regulator %s\n",
3731 rinfo->name);
3732 c++;
3733 }
3734
3735 return 0;
3736
3737err_reg_enable_failed:
3738 venus_hfi_for_each_regulator_reverse_continue(device, rinfo, c)
3739 __disable_regulator(rinfo);
3740
3741 return rc;
3742}
3743
3744static int __disable_regulators(struct venus_hfi_device *device)
3745{
3746 struct regulator_info *rinfo;
3747 int rc = 0;
3748
3749 dprintk(VIDC_DBG, "Disabling regulators\n");
3750
3751 venus_hfi_for_each_regulator_reverse(device, rinfo)
3752 __disable_regulator(rinfo);
3753
3754 return rc;
3755}
3756
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -07003757static int __enable_subcaches(struct venus_hfi_device *device)
3758{
3759 int rc = 0;
3760 u32 c = 0;
3761 struct subcache_info *sinfo;
3762 u32 resource[VIDC_MAX_SUBCACHE_SIZE];
3763 struct hfi_resource_syscache_info_type *sc_res_info;
3764 struct hfi_resource_subcache_type *sc_res;
3765 struct vidc_resource_hdr rhdr;
3766
3767 if (!device->res->sys_cache_enabled)
3768 return 0;
3769
3770 memset((void *)resource, 0x0, (sizeof(u32) * VIDC_MAX_SUBCACHE_SIZE));
3771
3772 sc_res_info = (struct hfi_resource_syscache_info_type *)resource;
3773 sc_res = &(sc_res_info->rg_subcache_entries[0]);
3774
3775 /* Activate subcaches */
3776 venus_hfi_for_each_subcache(device, sinfo) {
3777 rc = llcc_slice_activate(sinfo->subcache);
3778 if (rc) {
3779 dprintk(VIDC_ERR, "Failed to activate %s: %d\n",
3780 sinfo->name, rc);
3781 continue;
3782 }
3783 sinfo->isactive = true;
3784
3785 /* Update the entry */
3786 sc_res[c].size = sinfo->subcache->llcc_slice_size;
3787 sc_res[c].sc_id = sinfo->subcache->llcc_slice_id;
3788 dprintk(VIDC_DBG, "Activate subcache %s\n", sinfo->name);
3789 c++;
3790 }
3791
3792 /* Set resource to Venus for activated subcaches */
3793 if (c) {
3794 dprintk(VIDC_DBG, "Setting Subcaches\n");
3795
3796 rhdr.resource_handle = sc_res_info; /* cookie */
3797 rhdr.resource_id = VIDC_RESOURCE_SYSCACHE;
3798
3799 sc_res_info->num_entries = c;
3800
3801 rc = __core_set_resource(device, &rhdr, (void *)sc_res_info);
3802 if (rc) {
3803 dprintk(VIDC_ERR, "Failed to set subcaches %d\n", rc);
3804 goto err_fail_set_subacaches;
3805 }
3806 }
3807
3808 venus_hfi_for_each_subcache(device, sinfo) {
3809 if (sinfo->isactive == true)
3810 sinfo->isset = true;
3811 }
3812
3813 dprintk(VIDC_DBG, "Activated & Set Subcaches to Venus\n");
3814
3815 return 0;
3816
3817err_fail_set_subacaches:
3818 __disable_subcaches(device);
3819
3820 return rc;
3821}
3822
3823static int __disable_subcaches(struct venus_hfi_device *device)
3824{
3825 struct subcache_info *sinfo;
3826 int rc = 0;
3827 u32 c = 0;
3828 u32 resource[VIDC_MAX_SUBCACHE_SIZE];
3829 struct hfi_resource_syscache_info_type *sc_res_info;
3830 struct hfi_resource_subcache_type *sc_res;
3831 struct vidc_resource_hdr rhdr;
3832
3833 if (!device->res->sys_cache_enabled)
3834 return 0;
3835
3836 dprintk(VIDC_DBG, "Disabling Subcaches\n");
3837
3838 memset((void *)resource, 0x0, (sizeof(u32) * VIDC_MAX_SUBCACHE_SIZE));
3839
3840 sc_res_info = (struct hfi_resource_syscache_info_type *)resource;
3841 sc_res = &(sc_res_info->rg_subcache_entries[0]);
3842
3843 /* Release resource command to Venus */
3844 venus_hfi_for_each_subcache_reverse(device, sinfo) {
3845 if (sinfo->isset == true) {
3846 /* Update the entry */
3847 sc_res[c].size = sinfo->subcache->llcc_slice_size;
3848 sc_res[c].sc_id = sinfo->subcache->llcc_slice_id;
3849 c++;
3850 sinfo->isset = false;
3851 }
3852 }
3853
3854 if (c > 0) {
3855 rhdr.resource_handle = sc_res_info; /* cookie */
3856 rhdr.resource_id = VIDC_RESOURCE_SYSCACHE;
3857
3858 rc = __core_release_resource(device, &rhdr);
3859 if (rc)
3860 dprintk(VIDC_ERR, "Failed to release subcaches\n");
3861
3862 dprintk(VIDC_DBG, "Release %d subcaches\n", c);
3863 }
3864
3865 /* De-activate subcaches */
3866 venus_hfi_for_each_subcache_reverse(device, sinfo) {
3867 if (sinfo->isactive == true) {
3868 dprintk(VIDC_DBG, "De-activate subcache %s\n",
3869 sinfo->name);
3870 rc = llcc_slice_deactivate(sinfo->subcache);
3871 if (rc) {
3872 dprintk(VIDC_ERR,
3873 "Failed to de-activate %s: %d\n",
3874 sinfo->name, rc);
3875 }
3876 sinfo->isactive = false;
3877 }
3878 }
3879
3880 return rc;
3881}
3882
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003883static int __venus_power_on(struct venus_hfi_device *device)
3884{
3885 int rc = 0;
3886
3887 if (device->power_enabled)
3888 return 0;
3889
3890 device->power_enabled = true;
3891 /* Vote for all hardware resources */
3892 rc = __vote_buses(device, device->bus_vote.data,
3893 device->bus_vote.data_count);
3894 if (rc) {
3895 dprintk(VIDC_ERR, "Failed to vote buses, err: %d\n", rc);
3896 goto fail_vote_buses;
3897 }
3898
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003899 rc = __enable_regulators(device);
3900 if (rc) {
3901 dprintk(VIDC_ERR, "Failed to enable GDSC, err = %d\n", rc);
3902 goto fail_enable_gdsc;
3903 }
3904
3905 rc = __prepare_enable_clks(device);
3906 if (rc) {
3907 dprintk(VIDC_ERR, "Failed to enable clocks: %d\n", rc);
3908 goto fail_enable_clks;
3909 }
3910
Praneeth Paladugub71968b2015-08-19 20:47:57 -07003911 rc = __scale_clocks(device);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003912 if (rc) {
3913 dprintk(VIDC_WARN,
3914 "Failed to scale clocks, performance might be affected\n");
3915 rc = 0;
3916 }
3917
3918 /*
3919 * Re-program all of the registers that get reset as a result of
3920 * regulator_disable() and _enable()
3921 */
3922 __set_registers(device);
3923
3924 __write_register(device, VIDC_WRAPPER_INTR_MASK,
3925 VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK);
3926 device->intr_status = 0;
3927 enable_irq(device->hal_data->irq);
3928
3929 /*
3930 * Hand off control of regulators to h/w _after_ enabling clocks.
3931 * Note that the GDSC will turn off when switching from normal
3932 * (s/w triggered) to fast (HW triggered) unless the h/w vote is
3933 * present. Since Venus isn't up yet, the GDSC will be off briefly.
3934 */
3935 if (__enable_hw_power_collapse(device))
3936 dprintk(VIDC_ERR, "Failed to enabled inter-frame PC\n");
3937
3938 return rc;
3939
3940fail_enable_clks:
3941 __disable_regulators(device);
3942fail_enable_gdsc:
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003943 __unvote_buses(device);
3944fail_vote_buses:
3945 device->power_enabled = false;
3946 return rc;
3947}
3948
Maheshwar Ajja1e0d5312017-04-14 12:14:30 -07003949static void __venus_power_off(struct venus_hfi_device *device)
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003950{
3951 if (!device->power_enabled)
3952 return;
3953
3954 if (!(device->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
3955 disable_irq_nosync(device->hal_data->irq);
3956 device->intr_status = 0;
3957
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003958 __disable_unprepare_clks(device);
3959 if (__disable_regulators(device))
3960 dprintk(VIDC_WARN, "Failed to disable regulators\n");
3961
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003962 if (__unvote_buses(device))
3963 dprintk(VIDC_WARN, "Failed to unvote for buses\n");
3964 device->power_enabled = false;
3965}
3966
3967static inline int __suspend(struct venus_hfi_device *device)
3968{
3969 int rc = 0;
3970
3971 if (!device) {
3972 dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
3973 return -EINVAL;
3974 } else if (!device->power_enabled) {
3975 dprintk(VIDC_DBG, "Power already disabled\n");
3976 return 0;
3977 }
3978
3979 dprintk(VIDC_PROF, "Entering power collapse\n");
3980
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -07003981 if (__disable_subcaches(device))
3982 dprintk(VIDC_ERR, "Failed to disable subcaches\n");
3983
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003984 if (device->res->pm_qos_latency_us &&
3985 pm_qos_request_active(&device->qos))
3986 pm_qos_remove_request(&device->qos);
3987
3988 rc = __tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
3989 if (rc) {
3990 dprintk(VIDC_WARN, "Failed to suspend video core %d\n", rc);
3991 goto err_tzbsp_suspend;
3992 }
3993
Maheshwar Ajja1e0d5312017-04-14 12:14:30 -07003994 __venus_power_off(device);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08003995 dprintk(VIDC_PROF, "Venus power collapsed\n");
3996 return rc;
3997
3998err_tzbsp_suspend:
3999 return rc;
4000}
4001
4002static inline int __resume(struct venus_hfi_device *device)
4003{
4004 int rc = 0;
4005
4006 if (!device) {
4007 dprintk(VIDC_ERR, "Invalid params: %pK\n", device);
4008 return -EINVAL;
4009 } else if (device->power_enabled) {
4010 dprintk(VIDC_DBG, "Power is already enabled\n");
4011 goto exit;
4012 } else if (!__core_in_valid_state(device)) {
4013 dprintk(VIDC_DBG, "venus_hfi_device in deinit state.");
4014 return -EINVAL;
4015 }
4016
4017 dprintk(VIDC_PROF, "Resuming from power collapse\n");
4018 rc = __venus_power_on(device);
4019 if (rc) {
4020 dprintk(VIDC_ERR, "Failed to power on venus\n");
4021 goto err_venus_power_on;
4022 }
4023
4024 /* Reboot the firmware */
4025 rc = __tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESUME);
4026 if (rc) {
4027 dprintk(VIDC_ERR, "Failed to resume video core %d\n", rc);
4028 goto err_set_video_state;
4029 }
4030
4031 __setup_ucregion_memory_map(device);
4032 /* Wait for boot completion */
4033 rc = __boot_firmware(device);
4034 if (rc) {
4035 dprintk(VIDC_ERR, "Failed to reset venus core\n");
4036 goto err_reset_core;
4037 }
4038
4039 /*
4040 * Work around for H/W bug, need to reprogram these registers once
4041 * firmware is out reset
4042 */
4043 __set_threshold_registers(device);
4044
4045 if (device->res->pm_qos_latency_us) {
4046#ifdef CONFIG_SMP
4047 device->qos.type = PM_QOS_REQ_AFFINE_IRQ;
4048 device->qos.irq = device->hal_data->irq;
4049#endif
4050 pm_qos_add_request(&device->qos, PM_QOS_CPU_DMA_LATENCY,
4051 device->res->pm_qos_latency_us);
4052 }
Shivendra Kakraniac1f60e02017-04-13 00:07:26 -07004053
4054 __sys_set_debug(device, msm_vidc_fw_debug);
4055
4056 rc = __enable_subcaches(device);
4057 if (rc) {
4058 dprintk(VIDC_WARN,
4059 "Failed to enable subcaches, err = %d\n", rc);
4060 }
4061
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08004062 dprintk(VIDC_PROF, "Resumed from power collapse\n");
4063exit:
4064 device->skip_pc_count = 0;
4065 return rc;
4066err_reset_core:
4067 __tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
4068err_set_video_state:
Maheshwar Ajja1e0d5312017-04-14 12:14:30 -07004069 __venus_power_off(device);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08004070err_venus_power_on:
4071 dprintk(VIDC_ERR, "Failed to resume from power collapse\n");
4072 return rc;
4073}
4074
4075static int __load_fw(struct venus_hfi_device *device)
4076{
4077 int rc = 0;
4078
4079 /* Initialize resources */
4080 rc = __init_resources(device, device->res);
4081 if (rc) {
4082 dprintk(VIDC_ERR, "Failed to init resources: %d\n", rc);
4083 goto fail_init_res;
4084 }
4085
4086 rc = __initialize_packetization(device);
4087 if (rc) {
4088 dprintk(VIDC_ERR, "Failed to initialize packetization\n");
4089 goto fail_init_pkt;
4090 }
4091 trace_msm_v4l2_vidc_fw_load_start("msm_v4l2_vidc venus_fw load start");
4092
4093 rc = __venus_power_on(device);
4094 if (rc) {
4095 dprintk(VIDC_ERR, "Failed to power on venus in in load_fw\n");
4096 goto fail_venus_power_on;
4097 }
4098
4099 if ((!device->res->use_non_secure_pil && !device->res->firmware_base)
4100 || device->res->use_non_secure_pil) {
4101 if (!device->resources.fw.cookie)
4102 device->resources.fw.cookie =
4103 subsystem_get_with_fwname("venus",
4104 device->res->fw_name);
4105
4106 if (IS_ERR_OR_NULL(device->resources.fw.cookie)) {
4107 dprintk(VIDC_ERR, "Failed to download firmware\n");
4108 device->resources.fw.cookie = NULL;
4109 rc = -ENOMEM;
4110 goto fail_load_fw;
4111 }
4112 }
4113
4114 if (!device->res->use_non_secure_pil && !device->res->firmware_base) {
4115 rc = __protect_cp_mem(device);
4116 if (rc) {
4117 dprintk(VIDC_ERR, "Failed to protect memory\n");
4118 goto fail_protect_mem;
4119 }
4120 }
4121 trace_msm_v4l2_vidc_fw_load_end("msm_v4l2_vidc venus_fw load end");
4122 return rc;
4123fail_protect_mem:
4124 if (device->resources.fw.cookie)
4125 subsystem_put(device->resources.fw.cookie);
4126 device->resources.fw.cookie = NULL;
4127fail_load_fw:
Maheshwar Ajja1e0d5312017-04-14 12:14:30 -07004128 __venus_power_off(device);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08004129fail_venus_power_on:
4130fail_init_pkt:
4131 __deinit_resources(device);
4132fail_init_res:
4133 trace_msm_v4l2_vidc_fw_load_end("msm_v4l2_vidc venus_fw load end");
4134 return rc;
4135}
4136
4137static void __unload_fw(struct venus_hfi_device *device)
4138{
4139 if (!device->resources.fw.cookie)
4140 return;
4141
4142 cancel_delayed_work(&venus_hfi_pm_work);
4143 if (device->state != VENUS_STATE_DEINIT)
4144 flush_workqueue(device->venus_pm_workq);
4145
4146 __vote_buses(device, NULL, 0);
4147 subsystem_put(device->resources.fw.cookie);
4148 __interface_queues_release(device);
Maheshwar Ajja1e0d5312017-04-14 12:14:30 -07004149 __venus_power_off(device);
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08004150 device->resources.fw.cookie = NULL;
4151 __deinit_resources(device);
Maheshwar Ajjae43dd822017-04-25 15:56:53 -07004152
4153 dprintk(VIDC_PROF, "Firmware unloaded successfully\n");
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08004154}
4155
4156static int venus_hfi_get_fw_info(void *dev, struct hal_fw_info *fw_info)
4157{
4158 int i = 0, j = 0;
4159 struct venus_hfi_device *device = dev;
4160 u32 smem_block_size = 0;
4161 u8 *smem_table_ptr;
4162 char version[VENUS_VERSION_LENGTH];
4163 const u32 smem_image_index_venus = 14 * 128;
4164
4165 if (!device || !fw_info) {
4166 dprintk(VIDC_ERR,
4167 "%s Invalid parameter: device = %pK fw_info = %pK\n",
4168 __func__, device, fw_info);
4169 return -EINVAL;
4170 }
4171
4172 mutex_lock(&device->lock);
4173
4174 smem_table_ptr = smem_get_entry(SMEM_IMAGE_VERSION_TABLE,
4175 &smem_block_size, 0, SMEM_ANY_HOST_FLAG);
4176 if (smem_table_ptr &&
4177 ((smem_image_index_venus +
4178 VENUS_VERSION_LENGTH) <= smem_block_size))
4179 memcpy(version,
4180 smem_table_ptr + smem_image_index_venus,
4181 VENUS_VERSION_LENGTH);
4182
4183 while (version[i++] != 'V' && i < VENUS_VERSION_LENGTH)
4184 ;
4185
4186 if (i == VENUS_VERSION_LENGTH - 1) {
4187 dprintk(VIDC_WARN, "Venus version string is not proper\n");
4188 fw_info->version[0] = '\0';
4189 goto fail_version_string;
4190 }
4191
4192 for (i--; i < VENUS_VERSION_LENGTH && j < VENUS_VERSION_LENGTH - 1; i++)
4193 fw_info->version[j++] = version[i];
4194 fw_info->version[j] = '\0';
4195
4196fail_version_string:
4197 dprintk(VIDC_DBG, "F/W version retrieved : %s\n", fw_info->version);
4198 fw_info->base_addr = device->hal_data->firmware_base;
4199 fw_info->register_base = device->res->register_base;
4200 fw_info->register_size = device->hal_data->register_size;
4201 fw_info->irq = device->hal_data->irq;
4202
4203 mutex_unlock(&device->lock);
4204 return 0;
4205}
4206
4207static int venus_hfi_get_core_capabilities(void *dev)
4208{
4209 struct venus_hfi_device *device = dev;
4210 int rc = 0;
4211
4212 if (!device)
4213 return -EINVAL;
4214
4215 mutex_lock(&device->lock);
4216
4217 rc = HAL_VIDEO_ENCODER_ROTATION_CAPABILITY |
4218 HAL_VIDEO_ENCODER_SCALING_CAPABILITY |
4219 HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY |
4220 HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY;
4221
4222 mutex_unlock(&device->lock);
4223
4224 return rc;
4225}
4226
4227static int __initialize_packetization(struct venus_hfi_device *device)
4228{
4229 int rc = 0;
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08004230
4231 if (!device || !device->res) {
4232 dprintk(VIDC_ERR, "%s - invalid param\n", __func__);
4233 return -EINVAL;
4234 }
4235
Chinmay Sawarkar2de3f772017-02-07 12:03:44 -08004236 device->packetization_type = HFI_PACKETIZATION_4XX;
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08004237
4238 device->pkt_ops = hfi_get_pkt_ops_handle(device->packetization_type);
4239 if (!device->pkt_ops) {
4240 rc = -EINVAL;
4241 dprintk(VIDC_ERR, "Failed to get pkt_ops handle\n");
4242 }
4243
4244 return rc;
4245}
4246
4247static struct venus_hfi_device *__add_device(u32 device_id,
4248 struct msm_vidc_platform_resources *res,
4249 hfi_cmd_response_callback callback)
4250{
4251 struct venus_hfi_device *hdevice = NULL;
4252 int rc = 0;
4253
4254 if (!res || !callback) {
4255 dprintk(VIDC_ERR, "Invalid Parameters\n");
4256 return NULL;
4257 }
4258
4259 dprintk(VIDC_INFO, "entered , device_id: %d\n", device_id);
4260
4261 hdevice = (struct venus_hfi_device *)
4262 kzalloc(sizeof(struct venus_hfi_device), GFP_KERNEL);
4263 if (!hdevice) {
4264 dprintk(VIDC_ERR, "failed to allocate new device\n");
4265 goto exit;
4266 }
4267
4268 hdevice->response_pkt = kmalloc_array(max_packets,
4269 sizeof(*hdevice->response_pkt), GFP_KERNEL);
4270 if (!hdevice->response_pkt) {
4271 dprintk(VIDC_ERR, "failed to allocate response_pkt\n");
4272 goto err_cleanup;
4273 }
4274
4275 hdevice->raw_packet =
4276 kzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE, GFP_TEMPORARY);
4277 if (!hdevice->raw_packet) {
4278 dprintk(VIDC_ERR, "failed to allocate raw packet\n");
4279 goto err_cleanup;
4280 }
4281
4282 rc = __init_regs_and_interrupts(hdevice, res);
4283 if (rc)
4284 goto err_cleanup;
4285
4286 hdevice->res = res;
4287 hdevice->device_id = device_id;
4288 hdevice->callback = callback;
4289
4290 hdevice->vidc_workq = create_singlethread_workqueue(
4291 "msm_vidc_workerq_venus");
4292 if (!hdevice->vidc_workq) {
4293 dprintk(VIDC_ERR, ": create vidc workq failed\n");
4294 goto err_cleanup;
4295 }
4296
4297 hdevice->venus_pm_workq = create_singlethread_workqueue(
4298 "pm_workerq_venus");
4299 if (!hdevice->venus_pm_workq) {
4300 dprintk(VIDC_ERR, ": create pm workq failed\n");
4301 goto err_cleanup;
4302 }
4303
4304 if (!hal_ctxt.dev_count)
4305 INIT_LIST_HEAD(&hal_ctxt.dev_head);
4306
4307 mutex_init(&hdevice->lock);
4308 INIT_LIST_HEAD(&hdevice->list);
4309 INIT_LIST_HEAD(&hdevice->sess_head);
4310 list_add_tail(&hdevice->list, &hal_ctxt.dev_head);
4311 hal_ctxt.dev_count++;
4312
4313 return hdevice;
4314
4315err_cleanup:
4316 if (hdevice->vidc_workq)
4317 destroy_workqueue(hdevice->vidc_workq);
4318 kfree(hdevice->response_pkt);
4319 kfree(hdevice->raw_packet);
4320 kfree(hdevice);
4321exit:
4322 return NULL;
4323}
4324
4325static struct venus_hfi_device *__get_device(u32 device_id,
4326 struct msm_vidc_platform_resources *res,
4327 hfi_cmd_response_callback callback)
4328{
4329 if (!res || !callback) {
4330 dprintk(VIDC_ERR, "Invalid params: %pK %pK\n", res, callback);
4331 return NULL;
4332 }
4333
4334 return __add_device(device_id, res, callback);
4335}
4336
4337void venus_hfi_delete_device(void *device)
4338{
4339 struct venus_hfi_device *close, *tmp, *dev;
4340
4341 if (!device)
4342 return;
4343
4344 dev = (struct venus_hfi_device *) device;
4345
4346 mutex_lock(&dev->lock);
4347 __iommu_detach(dev);
4348 mutex_unlock(&dev->lock);
4349
4350 list_for_each_entry_safe(close, tmp, &hal_ctxt.dev_head, list) {
4351 if (close->hal_data->irq == dev->hal_data->irq) {
4352 hal_ctxt.dev_count--;
4353 list_del(&close->list);
4354 mutex_destroy(&close->lock);
4355 destroy_workqueue(close->vidc_workq);
4356 destroy_workqueue(close->venus_pm_workq);
4357 free_irq(dev->hal_data->irq, close);
4358 iounmap(dev->hal_data->register_base);
4359 kfree(close->hal_data);
4360 kfree(close->response_pkt);
4361 kfree(close->raw_packet);
4362 kfree(close);
4363 break;
4364 }
4365 }
4366}
4367
4368static void venus_init_hfi_callbacks(struct hfi_device *hdev)
4369{
4370 hdev->core_init = venus_hfi_core_init;
4371 hdev->core_release = venus_hfi_core_release;
4372 hdev->core_ping = venus_hfi_core_ping;
4373 hdev->core_trigger_ssr = venus_hfi_core_trigger_ssr;
4374 hdev->session_init = venus_hfi_session_init;
4375 hdev->session_end = venus_hfi_session_end;
4376 hdev->session_abort = venus_hfi_session_abort;
4377 hdev->session_clean = venus_hfi_session_clean;
4378 hdev->session_set_buffers = venus_hfi_session_set_buffers;
4379 hdev->session_release_buffers = venus_hfi_session_release_buffers;
4380 hdev->session_load_res = venus_hfi_session_load_res;
4381 hdev->session_release_res = venus_hfi_session_release_res;
4382 hdev->session_start = venus_hfi_session_start;
4383 hdev->session_continue = venus_hfi_session_continue;
4384 hdev->session_stop = venus_hfi_session_stop;
4385 hdev->session_etb = venus_hfi_session_etb;
4386 hdev->session_ftb = venus_hfi_session_ftb;
4387 hdev->session_process_batch = venus_hfi_session_process_batch;
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08004388 hdev->session_get_buf_req = venus_hfi_session_get_buf_req;
4389 hdev->session_flush = venus_hfi_session_flush;
4390 hdev->session_set_property = venus_hfi_session_set_property;
4391 hdev->session_get_property = venus_hfi_session_get_property;
4392 hdev->scale_clocks = venus_hfi_scale_clocks;
4393 hdev->vote_bus = venus_hfi_vote_buses;
4394 hdev->get_fw_info = venus_hfi_get_fw_info;
4395 hdev->get_core_capabilities = venus_hfi_get_core_capabilities;
4396 hdev->suspend = venus_hfi_suspend;
4397 hdev->flush_debug_queue = venus_hfi_flush_debug_queue;
Praneeth Paladugu6e6fbdb2017-01-16 15:43:01 -08004398 hdev->get_default_properties = venus_hfi_get_default_properties;
4399}
4400
4401int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
4402 struct msm_vidc_platform_resources *res,
4403 hfi_cmd_response_callback callback)
4404{
4405 int rc = 0;
4406
4407 if (!hdev || !res || !callback) {
4408 dprintk(VIDC_ERR, "Invalid params: %pK %pK %pK\n",
4409 hdev, res, callback);
4410 rc = -EINVAL;
4411 goto err_venus_hfi_init;
4412 }
4413
4414 hdev->hfi_device_data = __get_device(device_id, res, callback);
4415
4416 if (IS_ERR_OR_NULL(hdev->hfi_device_data)) {
4417 rc = PTR_ERR(hdev->hfi_device_data) ?: -EINVAL;
4418 goto err_venus_hfi_init;
4419 }
4420
4421 venus_init_hfi_callbacks(hdev);
4422
4423err_venus_hfi_init:
4424 return rc;
4425}
4426