1 #include "cmdq_driver.h"
2 #include "cmdq_struct.h"
6 #include "cmdq_device.h"
7 #include "cmdq_platform.h"
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
14 #include <linux/proc_fs.h>
15 #include <linux/seq_file.h>
17 #include <linux/cdev.h>
18 #include <linux/interrupt.h>
19 #include <linux/uaccess.h>
20 #include <linux/errno.h>
21 #include <linux/slab.h>
22 #include <linux/spinlock.h>
23 #include <linux/sched.h>
25 #include <linux/suspend.h>
27 #ifndef CMDQ_OF_SUPPORT
28 #include <mach/mt_irq.h> // mt_irq.h is not available on device tree enabled platforms
31 #ifdef CMDQ_OF_SUPPORT
33 * @device tree porting note
34 * alps/kernel-3.10/arch/arm64/boot/dts/{platform}.dts
35 * - use of_device_id to match driver and device
36 * - use io_map to map and get VA of HW's rgister
38 static const struct of_device_id cmdq_of_ids
[] = {
39 {.compatible
= "mediatek,GCE",},
44 #define CMDQ_MAX_DUMP_REG_COUNT (2048)
45 #define CMDQ_MAX_COMMAND_SIZE (0x10000)
46 #define CMDQ_MAX_WRITE_ADDR_COUNT (PAGE_SIZE / sizeof(u32))
48 static dev_t gCmdqDevNo
;
49 static struct cdev
*gCmdqCDev
;
50 static struct class *gCMDQClass
;
52 static ssize_t
cmdq_driver_dummy_write(struct device
*dev
,
53 struct device_attribute
*attr
, const char *buf
, size_t size
)
58 static DEVICE_ATTR(status
, S_IRUSR
| S_IWUSR
, cmdqCorePrintStatus
, cmdq_driver_dummy_write
);
59 static DEVICE_ATTR(error
, S_IRUSR
| S_IWUSR
, cmdqCorePrintError
, cmdq_driver_dummy_write
);
60 static DEVICE_ATTR(record
, S_IRUSR
| S_IWUSR
, cmdqCorePrintRecord
, cmdq_driver_dummy_write
);
61 static DEVICE_ATTR(log_level
, S_IRUSR
| S_IWUSR
, cmdqCorePrintLogLevel
, cmdqCoreWriteLogLevel
);
62 static DEVICE_ATTR(profile_enable
, S_IRUSR
| S_IWUSR
, cmdqCorePrintProfileEnable
,
63 cmdqCoreWriteProfileEnable
);
66 static int cmdq_proc_status_open(struct inode
*inode
, struct file
*file
)
68 return single_open(file
, cmdqCorePrintStatusSeq
, inode
->i_private
);
71 static int cmdq_proc_error_open(struct inode
*inode
, struct file
*file
)
73 return single_open(file
, cmdqCorePrintErrorSeq
, inode
->i_private
);
76 static int cmdq_proc_record_open(struct inode
*inode
, struct file
*file
)
78 return single_open(file
, cmdqCorePrintRecordSeq
, inode
->i_private
);
81 static const struct file_operations cmdqDebugStatusOp
= {
83 .open
= cmdq_proc_status_open
,
86 .release
= single_release
,
89 static const struct file_operations cmdqDebugErrorOp
= {
91 .open
= cmdq_proc_error_open
,
94 .release
= single_release
,
97 static const struct file_operations cmdqDebugRecordOp
= {
99 .open
= cmdq_proc_record_open
,
102 .release
= single_release
,
105 static int cmdq_open(struct inode
*pInode
, struct file
*pFile
)
107 cmdqFileNodeStruct
*pNode
;
109 CMDQ_VERBOSE("CMDQ driver open fd=%p begin\n", pFile
);
111 pFile
->private_data
= kzalloc(sizeof(cmdqFileNodeStruct
), GFP_KERNEL
);
112 if (NULL
== pFile
->private_data
) {
113 CMDQ_ERR("Can't allocate memory for CMDQ file node\n");
117 pNode
= (cmdqFileNodeStruct
*) pFile
->private_data
;
118 pNode
->userPID
= current
->pid
;
119 pNode
->userTGID
= current
->tgid
;
121 INIT_LIST_HEAD(&(pNode
->taskList
));
122 spin_lock_init(&pNode
->nodeLock
);
124 CMDQ_VERBOSE("CMDQ driver open end\n");
130 static int cmdq_release(struct inode
*pInode
, struct file
*pFile
)
132 cmdqFileNodeStruct
*pNode
;
135 CMDQ_VERBOSE("CMDQ driver release fd=%p begin\n", pFile
);
137 pNode
= (cmdqFileNodeStruct
*) pFile
->private_data
;
140 CMDQ_ERR("CMDQ file node NULL\n");
144 spin_lock_irqsave(&pNode
->nodeLock
, flags
);
146 /* note that we did not release CMDQ tasks */
147 /* issued by this file node, */
148 /* since their HW operation may be pending. */
150 spin_unlock_irqrestore(&pNode
->nodeLock
, flags
);
152 /* scan through tasks that created by this file node and release them */
153 cmdq_core_release_task_by_file_node((void *)pNode
);
155 if (NULL
!= pFile
->private_data
) {
156 kfree(pFile
->private_data
);
157 pFile
->private_data
= NULL
;
160 CMDQ_VERBOSE("CMDQ driver release end\n");
165 static int cmdq_driver_create_reg_address_buffer(cmdqCommandStruct
*pCommand
)
168 uint32_t totalRegCount
= 0;
169 uint32_t *regAddrBuf
= NULL
;
171 uint32_t *kernelRegAddr
= NULL
;
172 uint32_t kernelRegCount
= 0;
174 const uint32_t userRegCount
= pCommand
->regRequest
.count
;
177 if (0 != pCommand
->debugRegDump
) {
178 /* get kernel dump request count */
180 cmdqCoreDebugRegDumpBegin(pCommand
->debugRegDump
, &kernelRegCount
,
184 ("cmdqCoreDebugRegDumpBegin returns %d, ignore kernel reg dump request\n",
187 kernelRegAddr
= NULL
;
191 /* how many register to dump? */
192 if (kernelRegCount
> CMDQ_MAX_DUMP_REG_COUNT
|| userRegCount
> CMDQ_MAX_DUMP_REG_COUNT
)
194 totalRegCount
= kernelRegCount
+ userRegCount
;
196 if (0 == totalRegCount
) {
197 /* no need to dump register */
198 pCommand
->regRequest
.count
= 0;
199 pCommand
->regValue
.count
= 0;
200 pCommand
->regRequest
.regAddresses
= NULL
;
201 pCommand
->regValue
.regValues
= NULL
;
203 regAddrBuf
= kzalloc(totalRegCount
* sizeof(uint32_t), GFP_KERNEL
);
204 if (NULL
== regAddrBuf
) {
208 /* collect user space dump request */
211 (regAddrBuf
, CMDQ_U32_PTR(pCommand
->regRequest
.regAddresses
),
212 userRegCount
* sizeof(uint32_t))) {
218 /* collect kernel space dump request, concatnate after user space request */
219 if (kernelRegCount
) {
220 memcpy(regAddrBuf
+ userRegCount
, kernelRegAddr
,
221 kernelRegCount
* sizeof(uint32_t));
225 /* replace address buffer and value address buffer with kzalloc memory */
226 pCommand
->regRequest
.regAddresses
= regAddrBuf
;
227 pCommand
->regRequest
.count
= totalRegCount
;
233 static void cmdq_driver_process_read_address_request(cmdqReadAddressStruct
*req_user
)
235 /* create kernel-space buffer for working */
236 uint32_t *addrs
= NULL
;
237 uint32_t *values
= NULL
;
241 CMDQ_LOG("[READ_PA] cmdq_driver_process_read_address_request()\n");
244 if (NULL
== req_user
||
245 0 == req_user
->count
||
246 req_user
->count
> CMDQ_MAX_DUMP_REG_COUNT
||
247 NULL
== req_user
->values
|| NULL
== req_user
->dmaAddresses
) {
248 CMDQ_ERR("[READ_PA] invalid req_user\n");
252 addrs
= kzalloc(req_user
->count
* sizeof(uint32_t), GFP_KERNEL
);
254 CMDQ_ERR("[READ_PA] fail to alloc addr buf\n");
258 values
= kzalloc(req_user
->count
* sizeof(uint32_t), GFP_KERNEL
);
259 if (NULL
== values
) {
260 CMDQ_ERR("[READ_PA] fail to alloc value buf\n");
266 (addrs
, req_user
->dmaAddresses
, req_user
->count
* sizeof(uint32_t))) {
267 CMDQ_ERR("[READ_PA] fail to copy user dmaAddresses\n");
271 /* actually read these PA write buffers */
272 for (i
= 0; i
< req_user
->count
; ++i
) {
273 pa
= (0xFFFFFFFF & addrs
[i
]);
274 CMDQ_LOG("[READ_PA] req read dma addresss 0x%pa\n", &pa
);
275 values
[i
] = cmdqCoreReadWriteAddress(pa
);
278 /* copy value to user */
279 if (copy_to_user(req_user
->values
, values
, req_user
->count
* sizeof(uint32_t))) {
280 CMDQ_ERR("[READ_PA] fail to copy to user value buf\n");
297 static long cmdq_driver_destroy_secure_medadata(cmdqCommandStruct
*pCommand
)
299 if (pCommand
->secData
.addrMetadatas
) {
300 kfree(CMDQ_U32_PTR(pCommand
->secData
.addrMetadatas
));
301 pCommand
->secData
.addrMetadatas
= NULL
;
307 static long cmdq_driver_create_secure_medadata(cmdqCommandStruct
*pCommand
)
309 void *pAddrMetadatas
= NULL
;
310 const uint32_t length
= (pCommand
->secData
.addrMetadataCount
) * sizeof(cmdqSecAddrMetadataStruct
);
312 /* verify parameter */
313 if ((false == pCommand
->secData
.isSecure
) &&
314 (0 != pCommand
->secData
.addrMetadataCount
)) {
316 /* normal path with non-zero secure metadata */
317 CMDQ_ERR("[secData]mismatch secData.isSecure(%d) and secData.addrMetadataCount(%d)\n",
318 pCommand
->secData
.isSecure
,
319 pCommand
->secData
.addrMetadataCount
);
323 /* revise max count field */
324 pCommand
->secData
.addrMetadataMaxCount
= pCommand
->secData
.addrMetadataCount
;
326 /* bypass 0 metadata case*/
327 if (0 == pCommand
->secData
.addrMetadataCount
) {
328 pCommand
->secData
.addrMetadatas
= NULL
;
332 /* create kernel-space buffer for working */
333 pAddrMetadatas
= kzalloc(length
, GFP_KERNEL
);
334 if (NULL
== pAddrMetadatas
) {
335 CMDQ_ERR("[secData]kzalloc for addrMetadatas failed, count:%d, alloacted_size:%d\n",
336 pCommand
->secData
.addrMetadataCount
, length
);
341 if (copy_from_user(pAddrMetadatas
, pCommand
->secData
.addrMetadatas
, length
)) {
343 CMDQ_ERR("[secData]fail to copy user addrMetadatas\n");
345 /* replace buffer first to ensure that */
346 /* addrMetadatas is valid kernel space buffer address when free it */
347 pCommand
->secData
.addrMetadatas
= pAddrMetadatas
;
348 /* free secure path metadata */
349 cmdq_driver_destroy_secure_medadata(pCommand
);
354 pCommand
->secData
.addrMetadatas
= pAddrMetadatas
;
357 cmdq_core_dump_secure_metadata(&(pCommand
->secData
));
363 static long cmdq_driver_process_command_request(cmdqCommandStruct
*pCommand
)
366 uint32_t *userRegValue
= NULL
;
367 uint32_t userRegCount
= 0;
369 if (pCommand
->regRequest
.count
!= pCommand
->regValue
.count
) {
370 CMDQ_ERR("mismatch regRequest and regValue\n");
374 if (pCommand
->regRequest
.count
> CMDQ_MAX_DUMP_REG_COUNT
)
377 /* allocate secure medatata */
378 status
= cmdq_driver_create_secure_medadata(pCommand
);
383 /* backup since we are going to replace these */
384 userRegValue
= CMDQ_U32_PTR(pCommand
->regValue
.regValues
);
385 userRegCount
= pCommand
->regValue
.count
;
387 /* create kernel-space address buffer */
388 status
= cmdq_driver_create_reg_address_buffer(pCommand
);
390 /* free secure path metadata */
391 cmdq_driver_destroy_secure_medadata(pCommand
);
395 /* create kernel-space value buffer */
396 pCommand
->regValue
.regValues
= (cmdqU32Ptr_t
)(unsigned long)
397 kzalloc(pCommand
->regRequest
.count
* sizeof(uint32_t), GFP_KERNEL
);
398 pCommand
->regValue
.count
= pCommand
->regRequest
.count
;
399 if (NULL
== pCommand
->regValue
.regValues
) {
400 kfree(CMDQ_U32_PTR(pCommand
->regRequest
.regAddresses
));
404 /* scenario id fixup */
405 cmdq_core_fix_command_desc_scenario_for_user_space_request(pCommand
);
407 status
= cmdqCoreSubmitTask(pCommand
);
409 CMDQ_ERR("Submit user commands for execution failed = %d\n", status
);
410 cmdq_driver_destroy_secure_medadata(pCommand
);
412 kfree(CMDQ_U32_PTR(pCommand
->regRequest
.regAddresses
));
413 kfree(CMDQ_U32_PTR(pCommand
->regValue
.regValues
));
417 /* notify kernel space dump callback */
418 if (0 != pCommand
->debugRegDump
) {
419 status
= cmdqCoreDebugRegDumpEnd(pCommand
->debugRegDump
,
420 pCommand
->regRequest
.count
- userRegCount
,
421 CMDQ_U32_PTR(pCommand
->regValue
.regValues
) + userRegCount
);
423 CMDQ_ERR("cmdqCoreDebugRegDumpEnd returns %d\n", status
);
427 /* copy back to user space buffer */
428 if (userRegValue
&& userRegCount
) {
429 /* copy results back to user space */
430 CMDQ_VERBOSE("regValue[0] is %d\n", CMDQ_U32_PTR(pCommand
->regValue
.regValues
)[0]);
432 (userRegValue
, CMDQ_U32_PTR(pCommand
->regValue
.regValues
),
433 userRegCount
* sizeof(uint32_t))) {
434 CMDQ_ERR("Copy REGVALUE to user space failed\n");
438 /* free allocated kernel buffers */
439 kfree(CMDQ_U32_PTR(pCommand
->regRequest
.regAddresses
));
440 kfree(CMDQ_U32_PTR(pCommand
->regValue
.regValues
));
442 if (pCommand
->readAddress
.count
> 0) {
443 cmdq_driver_process_read_address_request(&pCommand
->readAddress
);
446 /* free allocated secure metadata */
447 cmdq_driver_destroy_secure_medadata(pCommand
);
452 static long cmdq_ioctl(struct file
*pFile
, unsigned int code
, unsigned long param
)
454 struct cmdqCommandStruct command
;
455 struct cmdqJobStruct job
;
456 int count
[CMDQ_MAX_ENGINE_COUNT
];
457 struct TaskStruct
*pTask
;
459 struct cmdqJobResultStruct jobResult
;
460 uint32_t *userRegValue
= NULL
;
461 uint32_t userRegCount
= 0;
462 /* backup value after task release */
463 uint32_t regCount
= 0, regCountUserSpace
= 0, regUserToken
= 0;
466 case CMDQ_IOCTL_EXEC_COMMAND
:
467 if (copy_from_user(&command
, (void *)param
, sizeof(cmdqCommandStruct
))) {
471 if (command
.regRequest
.count
> CMDQ_MAX_DUMP_REG_COUNT
||
472 !command
.blockSize
||
473 command
.blockSize
> CMDQ_MAX_COMMAND_SIZE
)
476 /* insert private_data for resource reclaim */
477 command
.privateData
= (void *)pFile
->private_data
;
479 if (cmdq_driver_process_command_request(&command
)) {
483 case CMDQ_IOCTL_QUERY_USAGE
:
484 if (cmdqCoreQueryUsage(count
)) {
488 if (copy_to_user((void *)param
, count
, sizeof(int32_t) * CMDQ_MAX_ENGINE_COUNT
)) {
489 CMDQ_ERR("CMDQ_IOCTL_QUERY_USAGE copy_to_user failed\n");
493 case CMDQ_IOCTL_ASYNC_JOB_EXEC
:
494 if (copy_from_user(&job
, (void *)param
, sizeof(cmdqJobStruct
))) {
498 if (job
.command
.blockSize
> CMDQ_MAX_COMMAND_SIZE
)
501 /* not support secure path for async ioctl yet */
502 if (true == job
.command
.secData
.isSecure
) {
503 CMDQ_ERR("not support secure path for CMDQ_IOCTL_ASYNC_JOB_EXEC\n");
508 userRegCount
= job
.command
.regRequest
.count
;
510 /* insert private_data for resource reclaim */
511 job
.command
.privateData
= (void *)pFile
->private_data
;
513 /* create kernel-space address buffer */
514 status
= cmdq_driver_create_reg_address_buffer(&job
.command
);
519 /* scenario id fixup */
520 cmdq_core_fix_command_desc_scenario_for_user_space_request(&job
.command
);
522 status
= cmdqCoreSubmitTaskAsync(&job
.command
, NULL
, 0, &pTask
);
524 /* store user space request count in TaskStruct */
525 /* for later retrieval */
527 pTask
->regCountUserSpace
= userRegCount
;
528 pTask
->regUserToken
= job
.command
.debugRegDump
;
531 /* we don't need regAddress anymore, free it now */
532 kfree(CMDQ_U32_PTR(job
.command
.regRequest
.regAddresses
));
533 job
.command
.regRequest
.regAddresses
= NULL
;
536 job
.hJob
= (unsigned long)pTask
;
537 if (copy_to_user((void *)param
, (void *)&job
, sizeof(cmdqJobStruct
))) {
538 CMDQ_ERR("CMDQ_IOCTL_ASYNC_JOB_EXEC copy_to_user failed\n");
542 job
.hJob
= (unsigned long)NULL
;
546 case CMDQ_IOCTL_ASYNC_JOB_WAIT_AND_CLOSE
:
547 if (copy_from_user(&jobResult
, (void *)param
, sizeof(jobResult
))) {
548 CMDQ_ERR("copy_from_user jobResult fail\n");
552 /* verify job handle */
553 if (!cmdqIsValidTaskPtr((TaskStruct
*)(unsigned long)jobResult
.hJob
)) {
554 CMDQ_ERR("invalid task ptr = 0x%llx\n", jobResult
.hJob
);
557 pTask
= (TaskStruct
*)(unsigned long)jobResult
.hJob
;
558 if (pTask
->regCount
> CMDQ_MAX_DUMP_REG_COUNT
)
561 /* utility service, fill the engine flag. */
562 /* this is required by MDP. */
563 jobResult
.engineFlag
= pTask
->engineFlag
;
565 /* check if reg buffer suffices */
566 if (jobResult
.regValue
.count
< pTask
->regCountUserSpace
) {
567 jobResult
.regValue
.count
= pTask
->regCountUserSpace
;
568 if (copy_to_user((void *)param
, (void *)&jobResult
, sizeof(jobResult
))) {
569 CMDQ_ERR("copy_to_user fail, line=%d\n", __LINE__
);
572 CMDQ_ERR("insufficient register buffer\n");
576 /* inform client the actual read register count */
577 jobResult
.regValue
.count
= pTask
->regCountUserSpace
;
578 /* update user space before we replace the regValues pointer. */
579 if (copy_to_user((void *)param
, (void *)&jobResult
, sizeof(jobResult
))) {
580 CMDQ_ERR("copy_to_user fail line=%d\n", __LINE__
);
584 /* allocate kernel space result buffer */
585 /* which contains kernel + user space requests */
586 userRegValue
= jobResult
.regValue
.regValues
;
587 jobResult
.regValue
.regValues
=
588 kzalloc(pTask
->regCount
* sizeof(uint32_t), GFP_KERNEL
);
589 jobResult
.regValue
.count
= pTask
->regCount
;
590 if (NULL
== jobResult
.regValue
.regValues
) {
591 CMDQ_ERR("no reg value buffer\n");
595 /* backup value after task release */
596 regCount
= pTask
->regCount
;
597 regCountUserSpace
= pTask
->regCountUserSpace
;
598 regUserToken
= pTask
->regUserToken
;
600 /* make sure the task is running and wait for it */
601 status
= cmdqCoreWaitResultAndReleaseTask(pTask
,
604 (CMDQ_DEFAULT_TIMEOUT_MS
));
606 CMDQ_ERR("waitResultAndReleaseTask fail=%d\n", status
);
607 /* free kernel space result buffer */
608 kfree(jobResult
.regValue
.regValues
);
612 /* pTask is released, do not access it any more */
615 /* notify kernel space dump callback */
616 if (regCount
> regCountUserSpace
) {
617 CMDQ_VERBOSE("kernel space reg dump = %d, %d, %d\n", regCount
,
618 regCountUserSpace
, regUserToken
);
620 cmdqCoreDebugRegDumpEnd(regUserToken
, regCount
- regCountUserSpace
,
621 jobResult
.regValue
.regValues
+
624 CMDQ_ERR("cmdqCoreDebugRegDumpEnd returns %d\n", status
);
628 /* copy result to user space */
630 ((void *)userRegValue
, (void *)(unsigned long)jobResult
.regValue
.regValues
,
631 regCountUserSpace
* sizeof(uint32_t))) {
632 CMDQ_ERR("Copy REGVALUE to user space failed\n");
636 if (jobResult
.readAddress
.count
> 0) {
637 cmdq_driver_process_read_address_request(&jobResult
.readAddress
);
640 /* free kernel space result buffer */
641 kfree(jobResult
.regValue
.regValues
);
643 case CMDQ_IOCTL_ALLOC_WRITE_ADDRESS
:
645 cmdqWriteAddressStruct addrReq
;
646 dma_addr_t paStart
= 0;
648 CMDQ_LOG("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS\n");
650 if (copy_from_user(&addrReq
, (void *)param
, sizeof(addrReq
))) {
651 CMDQ_ERR("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS copy_from_user failed\n");
655 if (!addrReq
.count
|| addrReq
.count
> CMDQ_MAX_WRITE_ADDR_COUNT
) {
657 "CMDQ_IOCTL_ALLOC_WRITE_ADDRESS invalid alloc write addr count:%u\n",
662 status
= cmdqCoreAllocWriteAddress(addrReq
.count
, &paStart
);
665 ("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS cmdqCoreAllocWriteAddress() failed\n");
670 addrReq
.startPA
= (uint32_t) paStart
;
671 CMDQ_LOG("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS get 0x%08x\n", addrReq
.startPA
);
673 if (copy_to_user((void *)param
, &addrReq
, sizeof(addrReq
))) {
674 CMDQ_ERR("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS copy_to_user failed\n");
680 case CMDQ_IOCTL_FREE_WRITE_ADDRESS
:
682 cmdqWriteAddressStruct freeReq
;
684 CMDQ_LOG("CMDQ_IOCTL_FREE_WRITE_ADDRESS\n");
686 if (copy_from_user(&freeReq
, (void *)param
, sizeof(freeReq
))) {
687 CMDQ_ERR("CMDQ_IOCTL_FREE_WRITE_ADDRESS copy_from_user failed\n");
691 status
= cmdqCoreFreeWriteAddress(freeReq
.startPA
);
698 case CMDQ_IOCTL_READ_ADDRESS_VALUE
:
700 cmdqReadAddressStruct readReq
;
702 CMDQ_LOG("CMDQ_IOCTL_READ_ADDRESS_VALUE\n");
704 if (copy_from_user(&readReq
, (void *)param
, sizeof(readReq
))) {
705 CMDQ_ERR("CMDQ_IOCTL_READ_ADDRESS_VALUE copy_from_user failed\n");
709 /* this will copy result to readReq->values buffer */
710 cmdq_driver_process_read_address_request(&readReq
);
716 case CMDQ_IOCTL_QUERY_CAP_BITS
:
719 if (cmdq_core_support_wait_and_receive_event_in_same_tick()) {
720 capBits
|= (1L << CMDQ_CAP_WFE
);
722 capBits
&= ~(1L << CMDQ_CAP_WFE
);
725 if (copy_to_user((void *)param
, &capBits
, sizeof(int))) {
726 CMDQ_ERR("Copy capacity bits to user space failed\n");
732 CMDQ_ERR("unrecognized ioctl 0x%08x\n", code
);
739 static long cmdq_ioctl_compat(struct file
*pFile
, unsigned int code
, unsigned long param
)
744 case CMDQ_IOCTL_QUERY_USAGE
:
745 case CMDQ_IOCTL_EXEC_COMMAND
:
746 case CMDQ_IOCTL_ASYNC_JOB_EXEC
:
747 case CMDQ_IOCTL_ASYNC_JOB_WAIT_AND_CLOSE
:
748 case CMDQ_IOCTL_ALLOC_WRITE_ADDRESS
:
749 case CMDQ_IOCTL_FREE_WRITE_ADDRESS
:
750 case CMDQ_IOCTL_READ_ADDRESS_VALUE
:
751 case CMDQ_IOCTL_QUERY_CAP_BITS
:
752 // All ioctl structures should be the same size in 32-bit and 64-bit linux.
753 return cmdq_ioctl(pFile
, code
, param
);
754 case CMDQ_IOCTL_LOCK_MUTEX
:
755 case CMDQ_IOCTL_UNLOCK_MUTEX
:
756 CMDQ_ERR("[COMPAT]deprecated ioctl 0x%08x\n", code
);
759 CMDQ_ERR("[COMPAT]unrecognized ioctl 0x%08x\n", code
);
763 CMDQ_ERR("[COMPAT]unrecognized ioctl 0x%08x\n", code
);
771 static const struct file_operations cmdqOP
= {
772 .owner
= THIS_MODULE
,
774 .release
= cmdq_release
,
775 .unlocked_ioctl
= cmdq_ioctl
,
777 .compat_ioctl
= cmdq_ioctl_compat
,
781 static int cmdq_pm_notifier_cb(struct notifier_block
*nb
, unsigned long event
, void *ptr
)
784 case PM_SUSPEND_PREPARE
:/* Going to suspend the system */
785 /* The next stage is freeze process. */
786 /* We will queue all request in suspend callback, */
787 /* so don't care this stage*/
788 return NOTIFY_DONE
; /* don't care this event */
789 case PM_POST_SUSPEND
:
790 /* processes had resumed in previous stage (system resume callback) */
791 /* resume CMDQ driver to execute. */
792 cmdqCoreResumedNotifier();
793 return NOTIFY_OK
; /* process done */
800 /* Hibernation and suspend events */
801 static struct notifier_block cmdq_pm_notifier_block
= {
802 .notifier_call
= cmdq_pm_notifier_cb
,
806 static irqreturn_t
cmdq_irq_handler(int IRQ
, void *pDevice
)
810 bool handled
= false; /* we share IRQ bit with CQ-DMA, */
811 /* so it is possible that this handler */
812 /* is called but GCE does not have IRQ flag. */
814 if (cmdq_dev_get_irq_id() == IRQ
) {
815 irqStatus
= CMDQ_REG_GET32(CMDQ_CURR_IRQ_STATUS
) & 0x0FFFF;
816 for (index
= 0; (irqStatus
!= 0xFFFF) && index
< CMDQ_MAX_THREAD_COUNT
;
818 /* STATUS bit set to 0 means IRQ asserted */
819 if (irqStatus
& (1 << index
)) {
822 /* so we mark irqStatus to 1 to denote finished processing */
823 /* and we can early-exit if no more threads being asserted */
824 irqStatus
|= (1 << index
);
826 cmdqCoreHandleIRQ(index
);
829 } else if (cmdq_dev_get_irq_secure_id() == IRQ
){
830 CMDQ_ERR("receive secure IRQ %d in NWD\n", IRQ
);
835 cmdq_core_add_consume_task();
838 /* allow CQ-DMA to process this IRQ bit */
843 static int cmdq_create_debug_entries(void)
845 struct proc_dir_entry
*debugDirEntry
= NULL
;
846 debugDirEntry
= proc_mkdir(CMDQ_DRIVER_DEVICE_NAME
"_debug", NULL
);
848 struct proc_dir_entry
*entry
= NULL
;
849 entry
= proc_create("status", 0440, debugDirEntry
, &cmdqDebugStatusOp
);
850 entry
= proc_create("error", 0440, debugDirEntry
, &cmdqDebugErrorOp
);
851 entry
= proc_create("record", 0440, debugDirEntry
, &cmdqDebugRecordOp
);
857 static int cmdq_probe(struct platform_device
*pDevice
)
860 struct device
*object
;
862 CMDQ_MSG("CMDQ driver probe begin\n");
864 /* init cmdq device related data */
865 cmdq_dev_init(pDevice
);
867 /* init cmdq context */
868 cmdqCoreInitialize();
870 status
= alloc_chrdev_region(&gCmdqDevNo
, 0, 1, CMDQ_DRIVER_DEVICE_NAME
);
872 CMDQ_ERR("Get CMDQ device major number(%d) failed(%d)\n", gCmdqDevNo
, status
);
874 CMDQ_MSG("Get CMDQ device major number(%d) success(%d)\n", gCmdqDevNo
, status
);
877 /* ioctl access point (/dev/mtk_cmdq) */
878 gCmdqCDev
= cdev_alloc();
879 gCmdqCDev
->owner
= THIS_MODULE
;
880 gCmdqCDev
->ops
= &cmdqOP
;
882 status
= cdev_add(gCmdqCDev
, gCmdqDevNo
, 1);
884 gCMDQClass
= class_create(THIS_MODULE
, CMDQ_DRIVER_DEVICE_NAME
);
885 object
= device_create(gCMDQClass
, NULL
, gCmdqDevNo
, NULL
, CMDQ_DRIVER_DEVICE_NAME
);
888 request_irq(cmdq_dev_get_irq_id(), cmdq_irq_handler
, IRQF_TRIGGER_LOW
| IRQF_SHARED
,
889 CMDQ_DRIVER_DEVICE_NAME
, gCmdqCDev
);
891 CMDQ_ERR("Register cmdq driver irq handler(%d) failed(%d)\n", gCmdqDevNo
, status
);
895 /* although secusre CMDQ driver is responsible for handle secure IRQ, */
896 /* MUST registet secure IRQ to GIC in normal world to ensure it will be initialize correctly */
897 /* (that's because t-base does not support GIC init IRQ in secure world...) */
898 #ifdef CMDQ_SECURE_PATH_SUPPORT
900 request_irq(cmdq_dev_get_irq_secure_id(), cmdq_irq_handler
, IRQF_TRIGGER_LOW
,
901 CMDQ_DRIVER_DEVICE_NAME
, gCmdqCDev
);
902 CMDQ_MSG("register sec IRQ:%d\n", cmdq_dev_get_irq_secure_id());
904 CMDQ_ERR("Register cmdq driver secure irq handler(%d) failed(%d)\n", gCmdqDevNo
, status
);
909 /* global ioctl access point (/proc/mtk_cmdq) */
910 if (NULL
== proc_create(CMDQ_DRIVER_DEVICE_NAME
, 0644, NULL
, &cmdqOP
)) {
911 CMDQ_ERR("CMDQ procfs node create failed\n");
915 /* proc debug access point */
916 cmdq_create_debug_entries();
918 /* device attributes for debugging */
919 device_create_file(&pDevice
->dev
, &dev_attr_status
);
920 device_create_file(&pDevice
->dev
, &dev_attr_error
);
921 device_create_file(&pDevice
->dev
, &dev_attr_record
);
922 device_create_file(&pDevice
->dev
, &dev_attr_log_level
);
923 device_create_file(&pDevice
->dev
, &dev_attr_profile_enable
);
925 CMDQ_MSG("CMDQ driver probe end\n");
931 static int cmdq_remove(struct platform_device
*pDevice
)
933 disable_irq(cmdq_dev_get_irq_id());
935 device_remove_file(&pDevice
->dev
, &dev_attr_status
);
936 device_remove_file(&pDevice
->dev
, &dev_attr_error
);
937 device_remove_file(&pDevice
->dev
, &dev_attr_record
);
938 device_remove_file(&pDevice
->dev
, &dev_attr_log_level
);
939 device_remove_file(&pDevice
->dev
, &dev_attr_profile_enable
);
944 static int cmdq_suspend(struct device
*pDevice
)
946 return cmdqCoreSuspend();
950 static int cmdq_resume(struct device
*pDevice
)
952 return cmdqCoreResume();
955 static int cmdq_pm_restore_noirq(struct device
*pDevice
)
960 static struct dev_pm_ops cmdq_pm_ops
= {
961 .suspend
= cmdq_suspend
,
962 .resume
= cmdq_resume
,
967 .restore_noirq
= cmdq_pm_restore_noirq
,
971 static struct platform_driver gCmdqDriver
= {
973 .remove
= cmdq_remove
,
975 .name
= CMDQ_DRIVER_DEVICE_NAME
,
976 .owner
= THIS_MODULE
,
978 #ifdef CMDQ_OF_SUPPORT
979 .of_match_table
= cmdq_of_ids
,
984 static int __init
cmdq_init(void)
988 CMDQ_MSG("CMDQ driver init begin\n");
990 /* Initialize group callback */
991 cmdqCoreInitGroupCB();
993 /* Register MDP callback */
994 cmdqCoreRegisterCB(CMDQ_GROUP_MDP
,
995 cmdqMdpClockOn
, cmdqMdpDumpInfo
, cmdqMdpResetEng
, cmdqMdpClockOff
);
997 /* Register VENC callback */
998 cmdqCoreRegisterCB(CMDQ_GROUP_VENC
, NULL
, cmdqVEncDumpInfo
, NULL
, NULL
);
1000 status
= platform_driver_register(&gCmdqDriver
);
1002 CMDQ_ERR("Failed to register the CMDQ driver(%d)\n", status
);
1006 /* register pm notifier */
1007 status
= register_pm_notifier(&cmdq_pm_notifier_block
);
1009 CMDQ_ERR("Failed to register_pm_notifier(%d)\n", status
);
1013 CMDQ_MSG("CMDQ driver init end\n");
1019 static void __exit
cmdq_exit(void)
1023 CMDQ_MSG("CMDQ driver exit begin\n");
1025 device_destroy(gCMDQClass
, gCmdqDevNo
);
1027 class_destroy(gCMDQClass
);
1029 cdev_del(gCmdqCDev
);
1033 unregister_chrdev_region(gCmdqDevNo
, 1);
1035 platform_driver_unregister(&gCmdqDriver
);
1037 /* register pm notifier */
1038 status
= unregister_pm_notifier(&cmdq_pm_notifier_block
);
1040 CMDQ_ERR("Failed to unregister_pm_notifier(%d)\n", status
);
1043 /* Unregister MDP callback */
1044 cmdqCoreRegisterCB(CMDQ_GROUP_MDP
, NULL
, NULL
, NULL
, NULL
);
1046 /* Unregister VENC callback */
1047 cmdqCoreRegisterCB(CMDQ_GROUP_VENC
, NULL
, NULL
, NULL
, NULL
);
1049 /* De-Initialize group callback */
1050 cmdqCoreDeinitGroupCB();
1052 /* De-Initialize cmdq core */
1053 cmdqCoreDeInitialize();
1055 /* De-Initialize cmdq dev related data */
1058 CMDQ_MSG("CMDQ driver exit end\n");
1062 subsys_initcall(cmdq_init
);
1063 module_exit(cmdq_exit
);
1065 MODULE_DESCRIPTION("MTK CMDQ driver");
1066 MODULE_AUTHOR("Pablo<pablo.sun@mediatek.com>");
1067 MODULE_LICENSE("GPL");