/*
 *
 * Copyright (C) 2012-2019, Samsung Electronics Co., Ltd.
 *
 * Display driver, platform depended implementation
 */

#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <tee_internal_api.h>
#include <unistd.h>
#include <cache.h>

#include "board.h"
#include "bsp_common.h"
#include "dbg.h"
#include "disp_core.h"
#include "disp_regs.h"
#include "mtk_display.h"
#include "protect.h"
#include "secmap.h"
#include "tuiHal.h"

/* Display device state */
static struct disp_dev_params disp_dev;

/*
 *  PLATFORM DEPENDENT LOW LEVEL INTERFACE
 */

/* Get disp drv internal structure pointer */
struct disp_dev_params *get_disp_dev_params(void)
{
    return &disp_dev;
}

/* Protect/unprotect all display related devices */
static TEE_Result secureDisplay(bool do_protect)
{
    dbgPrintf(">> %s\n", __func__);
    TEE_Result ret = TEE_SUCCESS;

    if (do_protect) {
        if (mtk_display_protect_controller() != 0) {
            ret = TEE_ERROR_GENERIC;
        }
    } else {
        if (mtk_display_unprotect_controller() != 0) {
            ret = TEE_ERROR_GENERIC;
        }
    }

    dbgPrintf("<< %s\n", __func__);
    return ret;
}

/* Protect display controller */
TEE_Result tuiHalDisplayProtectController(void)
{
    dbgPrintf(">> %s\n", __func__);
    TEE_Result ret = TEE_SUCCESS;

    if (!disp_dev.tzpc_done) {
        ret = secureDisplay(true);
        if (ret == TEE_SUCCESS) {
            disp_dev.tzpc_done = true;
        }
    }
    dbgPrintf("<< %s\n", __func__);
    return ret;
}

/* Unprotect display controller */
TEE_Result tuiHalDisplayUnprotectController(void)
{
    dbgPrintf(">> %s\n", __func__);
    TEE_Result ret = TEE_SUCCESS;

    if (disp_dev.tzpc_done) {
        ret = secureDisplay(false);
        if (ret == TEE_SUCCESS) {
            disp_dev.tzpc_done = false;
        }
    }
    dbgPrintf("<< %s\n", __func__);
    return ret;
}

/* Protect display framebuffer */
TEE_Result tuiHalDisplayProtectFramebuffer(void)
{
    dbgPrintf(">> %s\n", __func__);
    TEE_Result ret = TEE_SUCCESS;

    if (!disp_dev.tzasc_done) {
        uint32_t total_size = disp_dev.physicalFbLen
                            + disp_dev.physicalWbLen
                            + disp_dev.physicalDbLen;
        if (!disp_dev.physicalFb || (total_size & 0xFFFF)) {
            dbgPrintf("physical FB is misconfigured\n");
            return TEE_ERROR_BAD_PARAMETERS;
        }

        if (mtk_display_protect_framebuffer(disp_dev.physicalFb, total_size) == 0) {
            disp_dev.tzasc_done = true;
        } else {
            ret = TEE_ERROR_GENERIC;
            dbgPrintf("protect_by_tzasc failed: %x\n", ret);
        }
    }
    dbgPrintf("<< %s\n", __func__);
    return ret;
}

/* Unprotect display framebuffer */
TEE_Result tuiHalDisplayUnprotectFramebuffer(void)
{
    dbgPrintf(">> %s\n", __func__);
    TEE_Result ret = TEE_SUCCESS;

    if (disp_dev.tzasc_done) {
        uint32_t total_size = disp_dev.physicalFbLen
                            + disp_dev.physicalWbLen
                            + disp_dev.physicalDbLen;
        if (!disp_dev.physicalFb || (total_size & 0xFFFF)) {
            dbgPrintf("physical FB is misconfigured\n");
            return TEE_ERROR_BAD_PARAMETERS;
        }

        if (mtk_display_unprotect_framebuffer(disp_dev.physicalFb, total_size) == 0) {
            disp_dev.tzasc_done = false;
        } else {
            ret = TEE_ERROR_GENERIC;
            dbgPrintf("unprotect_by_tzasc failed: %x\n", ret);
        }
    }
    dbgPrintf("<< %s\n", __func__);
    return ret;
}

/* Map the video controller registers into the driver address space */
TEE_Result tuiHalDisplayMapController(void)
{
    TEE_Result ret = TEE_SUCCESS;
    dbgPrintf(">> %s\n", __func__);

    if (mtk_display_map_controller() != 0) {
        ret = TEE_ERROR_GENERIC;
    }

    dbgPrintf("<< %s\n", __func__);
    return ret;
}

/* Unmap the video controller registers from the driver address space */
TEE_Result tuiHalDisplayUnMapController(void)
{
    TEE_Result ret = TEE_SUCCESS;
    dbgPrintf(">> %s\n", __func__);

    if (mtk_display_unmap_controller() != 0) {
        ret = TEE_ERROR_GENERIC;
    };

    dbgPrintf("<< %s\n", __func__);
    return ret;
}
