// File: /workspace/github_c_makefile_star2_O2/xiane[P]libvphevcodec/AML_HEVCEncoder.cpp
// Function: Wave4VpuSleepWake(AMVHEVCEncHandle_s*, unsigned int, int, unsigned short const*, unsigned int, unsigned int)
AMVEnc_Status Wave4VpuSleepWake(AMVHEVCEncHandle *Handle, u32 coreIdx, int iSleepWake, const u16* code, u32 size, u32 mode) {
    u32 regVal;
    vpu_buffer_t vb;
    u32 codeBase;
    u32 codeSize;
    u32 remapSize;
    uint32_t timeoutTicks = 0;

    (void)code;
    (void)size;

    if (vdi_wait_vpu_busy(coreIdx, VPU_BUSY_CHECK_TIMEOUT, W4_VPU_BUSY_STATUS) == -1) {
        VLOG(ERR, "Wave4VpuSleepWake timeout");
        reset_error = 1;
        return AMVENC_TIMEOUT;
    }

    if (iSleepWake == 1)  //saves
            {
        VpuWriteReg(coreIdx, W4_VPU_BUSY_STATUS, 1);
        VpuWriteReg(coreIdx, W4_RET_SUCCESS, 0);  //for debug
        VpuWriteReg(coreIdx, W4_CORE_INDEX, 0);

        VpuWriteReg(coreIdx, W4_COMMAND, SLEEP_VPU);
        VpuWriteReg(coreIdx, W4_VPU_HOST_INT_REQ, 1);
        if (vdi_wait_interrupt(0, VPU_BUSY_CHECK_TIMEOUT) == -1) {
            VLOG(ERR, "Wave4VpuSleepWake interrput error time out");
            reset_error = 1;
            return AMVENC_TIMEOUT;
        }

        regVal = VpuReadReg(coreIdx, W4_RET_SUCCESS);
        if (regVal == 0) {
            uint32_t reasonCode = VpuReadReg(coreIdx, W4_RET_FAIL_REASON);
            VLOG(ERR, "VPU Sleep (W4_RET_SUCCESS) failed(%d) REASON CODE(%08x) ", regVal, reasonCode);
            reset_error = 1;
            return AMVENC_HARDWARE;
        }
        VLOG(DEBUG, "VPU SLEEP Sucess");
    } else //restore
    {
        Uint32 hwOption = 0;

        vdi_get_common_memory(coreIdx, &vb);
        codeBase = vb.phys_addr;
        /* ALIGN TO 4KB */
        codeSize = (vb.size & ~0xfff);

        regVal = 0;
        VpuWriteReg(coreIdx, W4_PO_CONF, regVal);

        /* SW_RESET_SAFETY */
        regVal = mode; //W4_RST_BLOCK_ACLK_ALL | W4_RST_BLOCK_BCLK_ALL | W4_RST_BLOCK_CCLK_ALL;
        VpuWriteReg(coreIdx, W4_VPU_RESET_REQ, regVal);    // Reset All blocks

        /* Waiting reset done */
        if (vdi_wait_vpu_busy(coreIdx, VPU_BUSY_CHECK_TIMEOUT, W4_VPU_RESET_STATUS) == -1) {
            VpuWriteReg(coreIdx, W4_VPU_RESET_REQ, 0);
            VLOG(ERR, "VPU Wake Reset timeout");
            reset_error = 1;
            return AMVENC_TIMEOUT;
        }

        VpuWriteReg(coreIdx, W4_VPU_RESET_REQ, 0);
//        if (mode & 0xff000000)
//            vdi_clear_memory(0, stack_vb.phys_addr,stack_vb.size);
        /* remap page size */
        remapSize = (codeSize >> 12) & 0x1ff;
        regVal = 0x80000000 | (W4_REMAP_CODE_INDEX << 12) | (0 << 16) | (1 << 11) | remapSize;
        VpuWriteReg(coreIdx, W4_VPU_REMAP_CTRL, regVal);
        VpuWriteReg(coreIdx, W4_VPU_REMAP_VADDR, 0x00000000); /* DO NOT CHANGE! */
        VpuWriteReg(coreIdx, W4_VPU_REMAP_PADDR, codeBase);
        VpuWriteReg(coreIdx, W4_ADDR_CODE_BASE, codeBase);
        VpuWriteReg(coreIdx, W4_CODE_SIZE, codeSize);
        VpuWriteReg(coreIdx, W4_CODE_PARAM, 0);
        VpuWriteReg(coreIdx, W4_COMMAND_OPTION, 0);
        timeoutTicks = COMMAND_TIMEOUT * VCPU_CLOCK_IN_MHZ * (1000000 >> 15);
        timeoutTicks = timeoutTicks / 120;
        if (Handle->enc_width * Handle->enc_height <= 1280 * 720)
            timeoutTicks = timeoutTicks / 16; //  /8 == 20ms  /4 == 40 ms  /16 == 10ms
        else if (Handle->enc_width * Handle->enc_height <= 1920 * 1088)
            timeoutTicks = timeoutTicks / 8;
        else
            timeoutTicks = timeoutTicks / 2;
        VpuWriteReg(coreIdx, W4_TIMEOUT_CNT, timeoutTicks);

//        codeBase = (Uint32)stack_vb.phys_addr;
//        codeSize = (Uint32)stack_vb.size;
//        VpuWriteReg(coreIdx, W4_ADDR_STACK_BASE,     codeBase);
//        VpuWriteReg(coreIdx, W4_STACK_SIZE,          codeSize);

        VpuWriteReg(coreIdx, W4_HW_OPTION, hwOption);

        /* Interrupt */
        // for encoder interrupt
        regVal = (1 << W4_INT_ENC_PIC);
        regVal |= (1 << W4_INT_SLEEP_VPU);
        regVal |= (1 << W4_INT_SET_PARAM);
        // for decoder interrupt
        regVal |= (1 << W4_INT_DEC_PIC_HDR);
        regVal |= (1 << W4_INT_DEC_PIC);
        regVal |= (1 << W4_INT_QUERY_DEC);
        regVal |= (1 << W4_INT_SLEEP_VPU);
        regVal |= (1 << W4_INT_BSBUF_EMPTY);
        regVal = 0xfffff6ff; // remove wake up int bit 11
        VpuWriteReg(coreIdx, W4_VPU_VINT_ENABLE, regVal);

        VpuWriteReg(coreIdx, W4_VPU_BUSY_STATUS, 1);
        VpuWriteReg(coreIdx, W4_RET_SUCCESS, 0);  //for debug
        VpuWriteReg(coreIdx, W4_CORE_INDEX, 0);
        VpuWriteReg(coreIdx, W4_INST_INDEX, 0);
        VpuWriteReg(coreIdx, W4_COMMAND, INIT_VPU);
        VpuWriteReg(coreIdx, W4_VPU_HOST_INT_REQ, 1);
        VpuWriteReg(coreIdx, W4_VPU_REMAP_CORE_START, 1);

        if (vdi_wait_interrupt(0, VPU_BUSY_CHECK_TIMEOUT) == -1) {
            VLOG(ERR, "VPU Wake timeout");
            reset_error = 1;
            return AMVENC_TIMEOUT;
        }

        //if (vdi_wait_vpu_busy(coreIdx, VPU_BUSY_CHECK_TIMEOUT, W4_VPU_BUSY_STATUS) == -1) {
        //    VLOG(ERR, "VPU Wake timeout");
        //    reset_error = 1;
        //    return AMVENC_TIMEOUT;
        //}
        regVal = VpuReadReg(coreIdx, W4_RET_SUCCESS);
        if (regVal == 0) {
            uint32_t reasonCode = VpuReadReg(coreIdx, W4_RET_FAIL_REASON);
            VLOG(ERR, "VPU Wake(W4_RET_SUCCESS) failed(%d) REASON CODE(%08x) ", regVal, reasonCode);
            reset_error = 1;
            return AMVENC_HARDWARE;
        }
        VLOG(DEBUG, "VPU WAKE Sucess");
    }
    return AMVENC_SUCCESS;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movl %r9d, %r12d
movl %edx, %ebp
movl %esi, %ebx
movq %rdi, %r14
pushq $0x70
popq %rdx
movl %esi, %edi
movl $0x1388, %esi           # imm = 0x1388
callq 0x2060
cmpl $-0x1, %eax
je 0x4327
cmpl $0x1, %ebp
jne 0x4333
pushq $0x70
popq %rsi
pushq $0x1
popq %rbp
movl %ebx, %edi
movl %ebp, %edx
callq 0x2160
movl %ebx, %edi
movl $0x110, %esi            # imm = 0x110
xorl %edx, %edx
callq 0x2160
movl %ebx, %edi
movl $0x104, %esi            # imm = 0x104
xorl %edx, %edx
callq 0x2160
movl %ebx, %edi
movl $0x100, %esi            # imm = 0x100
movl $0x400, %edx            # imm = 0x400
callq 0x2160
pushq $0x38
popq %rsi
movl %ebx, %edi
movl %ebp, %edx
callq 0x2160
xorl %edi, %edi
movl $0x1388, %esi           # imm = 0x1388
callq 0x2360
cmpl $-0x1, %eax
je 0x44f7
movl %ebx, %edi
movl $0x110, %esi            # imm = 0x110
callq 0x2210
testl %eax, %eax
jne 0x4535
movl %ebx, %edi
movl $0x114, %esi            # imm = 0x114
callq 0x2210
leaq 0x279fd(%rip), %rdi     # 0x2bd1f
jmp 0x44e0
leaq 0x279ac(%rip), %rdi     # 0x2bcda
jmp 0x451c
leaq 0x8(%rsp), %r13
movl %ebx, %edi
movq %r13, %rsi
callq 0x2190
movq 0x8(%r13), %r15
movl (%r13), %ebp
movl %ebx, %edi
xorl %esi, %esi
xorl %edx, %edx
callq 0x2160
pushq $0x50
popq %rsi
movl %ebx, %edi
movl %r12d, %edx
callq 0x2160
pushq $0x54
popq %rdx
movl %ebx, %edi
movl $0x1388, %esi           # imm = 0x1388
callq 0x2060
cmpl $-0x1, %eax
je 0x4500
movl %ebp, %r12d
andl $0xfffff000, %r12d      # imm = 0xFFFFF000
pushq $0x50
popq %rsi
movl %ebx, %edi
xorl %edx, %edx
callq 0x2160
shrl $0xc, %ebp
andl $0x1ff, %ebp            # imm = 0x1FF
orl $0x80000800, %ebp       # imm = 0x80000800
pushq $0x60
popq %rsi
movl %ebx, %edi
movl %ebp, %edx
callq 0x2160
pushq $0x64
popq %rsi
movl %ebx, %edi
xorl %edx, %edx
callq 0x2160
pushq $0x68
popq %rsi
movl %ebx, %edi
movl %r15d, %edx
callq 0x2160
movl %ebx, %edi
movl $0x118, %esi            # imm = 0x118
movl %r15d, %edx
callq 0x2160
movl %ebx, %edi
movl $0x11c, %esi            # imm = 0x11C
movl %r12d, %edx
callq 0x2160
movl %ebx, %edi
movl $0x120, %esi            # imm = 0x120
xorl %edx, %edx
callq 0x2160
movl %ebx, %edi
movl $0x10c, %esi            # imm = 0x10C
xorl %edx, %edx
callq 0x2160
movl 0x10(%r14), %eax
imull 0xc(%r14), %eax
cmpl $0x1fe001, %eax         # imm = 0x1FE001
movl $0xfa, %ecx
movl $0x3e8, %esi            # imm = 0x3E8
cmovbl %ecx, %esi
cmpl $0xe1001, %eax          # imm = 0xE1001
pushq $0x7d
popq %rdx
cmovael %esi, %edx
movl %ebx, %edi
movl $0x134, %esi            # imm = 0x134
callq 0x2160
movl %ebx, %edi
movl $0x124, %esi            # imm = 0x124
xorl %edx, %edx
callq 0x2160
pushq $0x48
popq %rsi
movl %ebx, %edi
movl $0xfffff6ff, %edx       # imm = 0xFFFFF6FF
callq 0x2160
pushq $0x70
popq %rsi
pushq $0x1
popq %rbp
movl %ebx, %edi
movl %ebp, %edx
callq 0x2160
movl %ebx, %edi
movl $0x110, %esi            # imm = 0x110
xorl %edx, %edx
callq 0x2160
movl %ebx, %edi
movl $0x104, %esi            # imm = 0x104
xorl %edx, %edx
callq 0x2160
movl %ebx, %edi
movl $0x108, %esi            # imm = 0x108
xorl %edx, %edx
callq 0x2160
movl %ebx, %edi
movl $0x100, %esi            # imm = 0x100
movl %ebp, %edx
callq 0x2160
pushq $0x38
popq %rsi
movl %ebx, %edi
movl %ebp, %edx
callq 0x2160
pushq $0x6c
popq %rsi
movl %ebx, %edi
movl %ebp, %edx
callq 0x2160
xorl %edi, %edi
movl $0x1388, %esi           # imm = 0x1388
callq 0x2360
cmpl $-0x1, %eax
je 0x4515
movl %ebx, %edi
movl $0x110, %esi            # imm = 0x110
callq 0x2210
testl %eax, %eax
jne 0x4535
movl %ebx, %edi
movl $0x114, %esi            # imm = 0x114
callq 0x2210
leaq 0x278a0(%rip), %rdi     # 0x2bd80
xorl %esi, %esi
movl %eax, %edx
xorl %eax, %eax
callq 0x2050
pushq $0xa
popq %rdi
callq 0x2230
pushq $-0x25
jmp 0x452d
leaq 0x277f6(%rip), %rdi     # 0x2bcf4
jmp 0x451c
pushq $0x50
popq %rsi
movl %ebx, %edi
xorl %edx, %edx
callq 0x2160
leaq 0x27845(%rip), %rdi     # 0x2bd58
jmp 0x451c
leaq 0x27853(%rip), %rdi     # 0x2bd6f
xorl %eax, %eax
callq 0x2050
pushq $0xa
popq %rdi
callq 0x2230
pushq $-0x24
popq %rbp
movb $0x1, 0x2acbf(%rip)     # 0x2f1f4
movl %ebp, %eax
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq