/*
 * 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 "mtk_buffer.h"
#include "mt_emi_mpu.h"
#include "emi_mpu_v1.h"
#include "secmap.h"


//#include "mtk_generic.h"

struct fbInfo_t fb_info = {
	.xRes = X_RES,
	.yRes = Y_RES,
	.bitsPerPixel = 32,
	.lineLength = 0,
	.type = UFMT_RGBA8888,
	.fbSize = 0,
	.fbPhysAddr = 0,
	.fb_membit = 0,
};

struct buffer_info {
	uint32_t addr;
	int size;
};

static int mpu_protected;

int mpu_protect(uint64_t phy_start, uint64_t phy_end, int enable)
{
	int ret;
	static struct emi_region_info_t region_info_p;

	region_info_p.start = phy_start;
	region_info_p.end = phy_end;
	region_info_p.region = TUI_MEMORY_MPU_REGION_ID;

	TUI_LOGD("%s enable:%d, start:0x%lx, end:0x%lx\n",
			__func__, enable, (unsigned long int)phy_start, (unsigned long int)phy_end);

	if (enable)
		SET_ACCESS_PERMISSION(region_info_p.apc, 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_FORBIDDEN, \
			EMI_MPU_FORBIDDEN, EMI_MPU_FORBIDDEN, EMI_MPU_FORBIDDEN, EMI_MPU_SEC_RW, \
			EMI_MPU_FORBIDDEN, EMI_MPU_FORBIDDEN, EMI_MPU_FORBIDDEN, EMI_MPU_SEC_RW);
	else {
		SET_ACCESS_PERMISSION(region_info_p.apc, 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, \
			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);
		TUI_LOGD("%s enable:%d\n", __func__, enable);
	}
	
	ret = emi_mpu_set_protection(&region_info_p);
	if (ret) {
		TUI_LOGD("%s failed:%d\n", __func__, ret);
		return ret;
	}

	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, uint32_t fb_phys_membit)
{
	set_disp_fb_buffer(fb_phys_start, size, fb_phys_membit);

	return 0;
}

int mtk_display_map_controller()
{
	TUI_LOGV("%s\n", __func__);
#ifdef 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__);

#ifdef TUI_ENABLE_DISPLAY
	return disp_tui_protect_engines();
#else
	return 0;
#endif
}

int mtk_display_unprotect_controller()
{
	TUI_LOGV("%s\n", __func__);

#ifdef 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;
	uint64_t addr_start, addr_end, addr_membit;
	int addr_size;
	TUI_LOGD("%s fb(0x%x,0x%x)\n", __func__, phys_start, phys_size);

	if (mpu_protected == 0) {
		/*addr_start = phys_start;*/
		/*addr_end = addr_start + phys_size;*/
		addr_size = get_secure_buffer(&phys_start);
		addr_membit  = (uint64_t)get_disp_fb_membit();
		addr_start = phys_start | ((addr_membit << 32));
		addr_end = (addr_start | (addr_membit << 32)) + addr_size - 1;
	
		TUI_LOGD("%s se(0x%lx,0x%lx)\n", __func__, (unsigned long int)addr_start, (unsigned long int)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)
{
	uint64_t addr_start, addr_end, addr_membit;
	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;
		total_mem_size = phys_size;
		addr_end = addr_start + total_mem_size - 1;
		*/
		addr_size = get_secure_buffer(&phys_start);
		addr_membit  = (uint64_t)get_disp_fb_membit();
		addr_start = phys_start | ((addr_membit << 32));
		addr_end = (addr_start | (addr_membit << 32)) + addr_size - 1;

		TUI_LOGD("%s se(0x%lx,0x%lx)\n", __func__, (unsigned long int)addr_start, (unsigned long int)addr_end);

#if TUI_ENABLE_MPU
		mpu_protect(addr_start, addr_end, 0);
#endif
		mpu_protected = 0;
	}
	return 0;

}

int mtk_display_get_fb_info()
{
	TUI_LOGV("%s\n", __func__);

	return 0;
}

int mtk_display_start()
{
	TUI_LOGV("%s\n", __func__);
#ifdef TUI_ENABLE_DISPLAY
	return disp_tui_init();
#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);
	fb_info.fb_membit = get_disp_fb_membit();
#ifdef TUI_ENABLE_DISPLAY
	return disp_tui_pan_display(&fb_info);
#else
	return 0;
#endif
}
