/*
 * Copyright (C) 2020 Arm Limited.
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "drmutils.h"
#include "mali_gralloc_formats.h"
#include <exynos_format.h>

uint32_t drm_fourcc_from_handle(const private_handle_t *hnd)
{
	/* Clean the modifier bits in the internal format. */
	struct table_entry
	{
		uint64_t internal;
		uint32_t fourcc;
	};

	static table_entry table[] = {
		{ MALI_GRALLOC_FORMAT_INTERNAL_RAW16, DRM_FORMAT_R16 },
		{ MALI_GRALLOC_FORMAT_INTERNAL_RGBA_8888, DRM_FORMAT_ABGR8888 },
		{ MALI_GRALLOC_FORMAT_INTERNAL_BGRA_8888, DRM_FORMAT_ARGB8888 },
		{ MALI_GRALLOC_FORMAT_INTERNAL_RGB_565, DRM_FORMAT_RGB565 },
		{ MALI_GRALLOC_FORMAT_INTERNAL_RGBX_8888, DRM_FORMAT_XBGR8888 },
		{ MALI_GRALLOC_FORMAT_INTERNAL_RGB_888, DRM_FORMAT_BGR888 },
		{ MALI_GRALLOC_FORMAT_INTERNAL_RGBA_1010102, DRM_FORMAT_ABGR2101010 },
		{ MALI_GRALLOC_FORMAT_INTERNAL_RGBA_16161616, DRM_FORMAT_ABGR16161616F },
		{ MALI_GRALLOC_FORMAT_INTERNAL_YV12, DRM_FORMAT_YVU420 },
		{ MALI_GRALLOC_FORMAT_INTERNAL_NV12, DRM_FORMAT_NV12 },
		{ MALI_GRALLOC_FORMAT_INTERNAL_NV16, DRM_FORMAT_NV16 },
		{ MALI_GRALLOC_FORMAT_INTERNAL_NV21, DRM_FORMAT_NV21 },
		{ MALI_GRALLOC_FORMAT_INTERNAL_Y0L2, DRM_FORMAT_Y0L2 },
		{ MALI_GRALLOC_FORMAT_INTERNAL_Y210, DRM_FORMAT_Y210 },
		{ MALI_GRALLOC_FORMAT_INTERNAL_P010, DRM_FORMAT_P010 },
		{ MALI_GRALLOC_FORMAT_INTERNAL_P210, DRM_FORMAT_P210 },
		{ MALI_GRALLOC_FORMAT_INTERNAL_Y410, DRM_FORMAT_Y410 },
		{ MALI_GRALLOC_FORMAT_INTERNAL_YUV422_8BIT, DRM_FORMAT_YUYV },
		{ MALI_GRALLOC_FORMAT_INTERNAL_YUV420_8BIT_I, DRM_FORMAT_YUV420_8BIT },
		{ MALI_GRALLOC_FORMAT_INTERNAL_YUV420_10BIT_I, DRM_FORMAT_YUV420_10BIT },

		/* Deprecated legacy formats, mapped to MALI_GRALLOC_FORMAT_INTERNAL_YUV422_8BIT. */
		{ HAL_PIXEL_FORMAT_YCbCr_422_I, DRM_FORMAT_YUYV },
		/* Deprecated legacy formats, mapped to MALI_GRALLOC_FORMAT_INTERNAL_NV21. */
		{ HAL_PIXEL_FORMAT_YCrCb_420_SP, DRM_FORMAT_NV21 },
		/* Format introduced in Android P, mapped to MALI_GRALLOC_FORMAT_INTERNAL_P010. */
		{ HAL_PIXEL_FORMAT_YCBCR_P010, DRM_FORMAT_P010 },

		/* Exynos Formats */
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP,  DRM_FORMAT_NV12 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M, DRM_FORMAT_NV21 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_FULL, DRM_FORMAT_NV21 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M, DRM_FORMAT_NV12 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YV12_M, DRM_FORMAT_YVU420 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P_M, DRM_FORMAT_NV12 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_S10B,  DRM_FORMAT_NV12 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_TILED, DRM_FORMAT_NV12 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN,        DRM_FORMAT_NV12 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_S10B,   DRM_FORMAT_NV12 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_SPN,       DRM_FORMAT_P010 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_P010_M,         DRM_FORMAT_P010 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P,          DRM_FORMAT_NV12 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC,         DRM_FORMAT_NV12 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC,          DRM_FORMAT_NV12 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC,     DRM_FORMAT_P010 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_SBWC,      DRM_FORMAT_P010 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_SBWC,         DRM_FORMAT_NV21 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCrCb_420_SP_M_10B_SBWC,     DRM_FORMAT_P010 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L50,     DRM_FORMAT_NV12 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_SBWC_L75,     DRM_FORMAT_NV12 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC_L50,      DRM_FORMAT_NV12 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_SBWC_L75,      DRM_FORMAT_NV12 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC_L40, DRM_FORMAT_P010 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC_L60, DRM_FORMAT_P010 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SP_M_10B_SBWC_L80, DRM_FORMAT_P010 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_SBWC_L40,  DRM_FORMAT_P010 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_SBWC_L60,  DRM_FORMAT_P010 },
		{ HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_SPN_10B_SBWC_L80,  DRM_FORMAT_P010 },

		/* Google Formats */
		{ HAL_PIXEL_FORMAT_GOOGLE_NV12_SP,      DRM_FORMAT_NV12 },
		{ HAL_PIXEL_FORMAT_GOOGLE_NV12_SP_10B,  DRM_FORMAT_P010 },
		{ HAL_PIXEL_FORMAT_GOOGLE_R_8,  DRM_FORMAT_R8 },
		{ HAL_PIXEL_FORMAT_GOOGLE_RG_88,  DRM_FORMAT_RG88 },
	};

	const uint64_t unmasked_format = hnd->alloc_format;
	const uint64_t internal_format = (unmasked_format & MALI_GRALLOC_INTFMT_FMT_MASK);
	for (size_t i = 0; i < sizeof(table) / sizeof(table[0]); i++)
	{
		if (table[i].internal == internal_format)
		{
			bool afbc = (unmasked_format & MALI_GRALLOC_INTFMT_AFBCENABLE_MASK);
			/* The internal RGB565 format describes two different component orderings depending on AFBC. */
			if (afbc && internal_format == MALI_GRALLOC_FORMAT_INTERNAL_RGB_565)
			{
				return DRM_FORMAT_BGR565;
			}
			return table[i].fourcc;
		}
	}

	return DRM_FORMAT_INVALID;
}

uint64_t drm_modifier_from_handle(const private_handle_t *hnd)
{
	const uint64_t internal_format = hnd->alloc_format;
	if ((internal_format & MALI_GRALLOC_INTFMT_AFBCENABLE_MASK) == 0)
	{
		return 0;
	}

	uint64_t modifier = 0;

	if (internal_format & MALI_GRALLOC_INTFMT_AFBC_SPLITBLK)
	{
		modifier |= AFBC_FORMAT_MOD_SPLIT;
	}

	if (internal_format & MALI_GRALLOC_INTFMT_AFBC_TILED_HEADERS)
	{
		modifier |= AFBC_FORMAT_MOD_TILED;
	}

	if (internal_format & MALI_GRALLOC_INTFMT_AFBC_DOUBLE_BODY)
	{
		modifier |= AFBC_FORMAT_MOD_DB;
	}

	if (internal_format & MALI_GRALLOC_INTFMT_AFBC_BCH)
	{
		modifier |= AFBC_FORMAT_MOD_BCH;
	}

	if (internal_format & MALI_GRALLOC_INTFMT_AFBC_YUV_TRANSFORM)
	{
		modifier |= AFBC_FORMAT_MOD_YTR;
	}

	if (internal_format & MALI_GRALLOC_INTFMT_AFBC_SPARSE)
	{
		modifier |= AFBC_FORMAT_MOD_SPARSE;
	}

	/* Extract the block-size modifiers. */
	if (internal_format & MALI_GRALLOC_INTFMT_AFBC_WIDEBLK)
	{
		modifier |= (hnd->is_multi_plane() ? AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4 : AFBC_FORMAT_MOD_BLOCK_SIZE_32x8);
	}
	else if (internal_format & MALI_GRALLOC_INTFMT_AFBC_EXTRAWIDEBLK)
	{
		modifier |= AFBC_FORMAT_MOD_BLOCK_SIZE_64x4;
	}
	else
	{
		modifier |= AFBC_FORMAT_MOD_BLOCK_SIZE_16x16;
	}

	return DRM_FORMAT_MOD_ARM_AFBC(modifier);
}