/*
 * Copyright (c) 2014 - 2016 MediaTek Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#define TAG "[disp]"
#include "mtk_log.h"

#include <tee_internal_api.h>
#include "mtk_display.h"
#include "display_tui.h"
#include "DrApiPlat.h"
#include "mtk_buffer.h"
#include "mtk_generic.h"

fbInfo_t fb_info = {
    .xRes = 1080,
    .yRes =1920,
    .bitsPerPixel = 32,
    .lineLength = 0,
    .type = UFMT_RGBA8888,
    .fbSize = 0,
    .fbPhysAddr = 0,
};

struct buffer_info {
    uint32_t addr;
    int size;
};

static int mpu_protected;

static int mpu_protect(uint32_t phy_start, uint32_t phy_end, int enable)
{
    static const unsigned int mpu_att_protec = SET_ACCESS_PERMISSON(EMI_MPU_UNLOCK, EMI_MPU_FORBIDDEN, EMI_MPU_FORBIDDEN,
                    EMI_MPU_FORBIDDEN, EMI_MPU_FORBIDDEN, EMI_MPU_FORBIDDEN, EMI_MPU_FORBIDDEN, EMI_MPU_FORBIDDEN, EMI_MPU_SEC_RW);
    static const unsigned int mpu_att_unprotec = SET_ACCESS_PERMISSON(EMI_MPU_UNLOCK, EMI_MPU_NO_PROTECTION, EMI_MPU_NO_PROTECTION,
                    EMI_MPU_NO_PROTECTION, EMI_MPU_NO_PROTECTION, EMI_MPU_NO_PROTECTION, EMI_MPU_NO_PROTECTION,
                    EMI_MPU_NO_PROTECTION, EMI_MPU_NO_PROTECTION);

    if(enable)
        emi_mpu_set_region_protection(phy_start, phy_end, TUI_MEMORY_MPU_REGION_ID, mpu_att_protec);
    else
        emi_mpu_set_region_protection(phy_start, phy_end, TUI_MEMORY_MPU_REGION_ID, mpu_att_unprotec);

    return 0;
}

int mtk_display_init()
{
    /* no register va can be used, do nothing*/
    TUI_LOGD("%s\n", __func__);

    return 0;
}

int mtk_display_deinit()
{
    TUI_LOGD("%s\n", __func__);
    clear_disp_wk_buffer();
    clear_touch_wk_buffer();
    clear_disp_fb_buffer();
    return 0;
}

int mtk_display_set_internal(uint32_t phys_addr, int phys_size)
{
    uint32_t pyh = 0;
    uint32_t size = 0;
    int ret = 0;

    TUI_LOGD("set wb (0x%x, 0x%x)\n", phys_addr, phys_size);

    ret = set_disp_wk_buffer(phys_addr, phys_size);
    if (ret != 0) {
        return -1;
    }
    size = require_cmdq_buffer(&pyh);
    if (size == 0) {
        TUI_LOGE("Fail to get cmdq buffer!!\n");
        return -1;
    }
    disp_set_wk_buffer(pyh, size);

    return 0;
}

int mtk_display_set_fb(uint32_t fb_phys_start, int size)
{
    set_disp_fb_buffer(fb_phys_start, size);

    return 0;
}

int mtk_display_map_controller()
{
    TUI_LOGV("%s\n", __func__);
#if TUI_ENABLE_DISPLAY
    return disp_tui_map_registers();
#else
    return 0;
#endif

}

int mtk_display_unmap_controller()
{
    TUI_LOGV("%s\n", __func__);

    return 0;
}

int mtk_display_protect_controller()
{
    TUI_LOGV("%s\n", __func__);

#if TUI_ENABLE_DISPLAY
    return disp_tui_protect_engines();
#else
    return 0;
#endif
}

int mtk_display_unprotect_controller()
{
    TUI_LOGV("%s\n", __func__);

#if TUI_ENABLE_DISPLAY
    return disp_tui_unprotect_engines();
#else
    return 0;
#endif
}

int mtk_display_protect_framebuffer(uint32_t phys_start, uint32_t phys_size)
{
    int ret = 0;
    uint32_t addr_start, addr_end;
    int addr_size = 0;
    TUI_LOGD("%s fb(0x%x,0x%x)\n", __func__, phys_start, phys_size);

    if (mpu_protected == 0) {
        addr_start = phys_start;
        addr_size = phys_size;
        addr_end = addr_start + addr_size - 1;
        TUI_LOGD("%s se(0x%x,0x%x)\n", __func__, addr_start, addr_end);
#if TUI_ENABLE_MPU
        mpu_protect(addr_start, addr_end, 1);
#endif
        mpu_protected = 1;
    }

    return ret;
}

int mtk_display_unprotect_framebuffer(uint32_t phys_start, uint32_t phys_size)
{
    uint32_t addr_start;
    uint32_t addr_end;
    int addr_size = 0;
    TUI_LOGD("%s fb(0x%x,0x%x)\n", __func__, phys_start, phys_size);

    if (mpu_protected) {
        addr_start = phys_start;
        addr_size = phys_size;
        addr_end = addr_start + addr_size - 1;
        TUI_LOGD("%s se(0x%x,0x%x)\n", __func__, addr_start, addr_end);
#if TUI_ENABLE_MPU
        mpu_protect(addr_start, addr_end, 0);
#endif
        mpu_protected = 0;
        clear_disp_wk_buffer();
        clear_touch_wk_buffer();
        clear_disp_fb_buffer();
    }
    return 0;

}

int mtk_display_get_fb_info()
{
    TUI_LOGV("%s\n", __func__);

    return 0;
}

int mtk_display_start()
{
    TUI_LOGV("%s\n", __func__);
#if TUI_ENABLE_DISPLAY
    return disp_tui_enable();
#else
    return 0;
#endif
}

int mtk_display_pan_display()
{
    TUI_LOGV("%s\n", __func__);
    fb_info.fbSize = get_disp_fb_buffer((uint32_t *)&(fb_info.fbPhysAddr));
    fb_info.lineLength = fb_info.xRes * (fb_info.bitsPerPixel >> 3);
#if TUI_ENABLE_DISPLAY
    return disp_tui_pan_display(&fb_info);
#else
    return 0;
#endif
}
