/* Copyright Statement:
 *
 * This software/firmware and related documentation ("MediaTek Software") are
 * protected under relevant copyright laws. The information contained herein is
 * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
 * the prior written permission of MediaTek inc. and/or its licensors, any
 * reproduction, modification, use or disclosure of MediaTek Software, and
 * information contained herein, in whole or in part, shall be strictly
 * prohibited.
 *
 * Copyright  (C) [2020]  MediaTek Inc. All rights reserved.
 *
 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
 * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
 * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
 * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
 * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
 * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
 * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
 * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
 * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
 * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
 * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
 * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
 * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
 * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
 * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
 *
 * The following software/firmware and/or related documentation ("MediaTek
 * Software") have been modified by MediaTek Inc. All revisions are subject to
 * any receiver's applicable license agreements with MediaTek Inc.
 */

#include <common.h>
#include <command.h>
#include "dts_parser.h"
#include "utility.h"
#include <debug_impl.h>
#include <boot_impl.h>
#include <adc.h>
#include <dm.h>
#include <upgrade_utility.h>
#include <romtblo_impl.h>
#include <ecinfo.h>
#if defined(CONFIG_MTK_PM)
#include <mtk-pm.h>
#endif

int do_boot_mode_check(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    int ret;
    ret = boot_mode_check();
    if(ret != 0)
    {
        UBOOT_DEBUG("Do boot mode check failure\n");
        return -1;
    }

    return 0;
}

U_BOOT_CMD(
    bootcheck,    1,    1,     do_boot_mode_check,
    "Mediatek boot mode check command",
    "command: bootcheck\n"
);

int do_fastboot_mode_check(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    int ret;
    ret = is_fastboot_mode();
    if (ret != 0)
    {
        // Platform-specific initialization for fastboot mode
#if defined(CONFIG_MULTICORES_PLATFORM) && (defined(CONFIG_ANDROID_WW_PLATFORM) || defined(CONFIG_ANDROID_CN_PLATFORM))
        set_panel_init_in_fastboot_mode();
#endif
        // Run device ID command
        ret = run_command("deviceid", 0);
        if (ret != 0)
        {
            UBOOT_ERROR("Failed to run deviceid\n");
            return ret;
        }
        // Enter fastboot mode
        ret = run_command("fastboot usb 0", 0);
        if (ret != 0)
        {
            UBOOT_ERROR("Failed to run fastboot usb 0\n");
            return ret;
        }
    }

    return 0;
}

U_BOOT_CMD(
    fastbootcheck,    1,    1,     do_fastboot_mode_check,
    "Mediatek fastboot mode check command",
    "command: fastbootcheck\n"
);

int do_fastboot_shortcut_check(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    int ret;
    ret = fastboot_shortcut_check();
    if (ret != 0)
    {
        UBOOT_DEBUG("Do fastboot shortcut check failure\n");
        return -1;
    }

    return 0;
}

U_BOOT_CMD(
    fastbootshortcutcheck,    1,    1,     do_fastboot_shortcut_check,
    "upgrade mode check command",
    "command: upgradecheck\n"
);

int do_upgrade_mode_check(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    int ret;
    ret = upgrade_mode_check();
    if(ret != 0)
    {
        UBOOT_DEBUG("Do boot mode check failure\n");
        return -1;
    }

    return 0;
}

U_BOOT_CMD(
    upgradecheck,    1,    1,     do_upgrade_mode_check,
    "upgrade mode check command",
    "command: upgradecheck\n"
);

#if defined(CONFIG_BOOT_IR)
int do_bootir_mode_check(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    int ret;
    ret = bootir_mode_check();
    if(ret != 0)
    {
        UBOOT_DEBUG("Do boot mode check failure\n");
        return -1;
    }

    return 0;
}

U_BOOT_CMD(
    bootircheck,    1,    1,     do_bootir_mode_check,
    "bootir mode check command",
    "command: bootircheck\n"
);
#endif

int do_propagate_mmap_filename(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
#define MAX_MMAP_FILENAME_LEN (128)
#define MAX_BUF_LEN (256)
    char mmap_filename[MAX_MMAP_FILENAME_LEN] = {0};
    char buf[MAX_BUF_LEN] = {0};

    UBOOT_DEBUG("do_propagate_mmap_filename\n");

    if(parse_dt("/mmap_info", string_dt_parser, mmap_filename, "mmap_filename"))
    {
        //node or field is not found; notify error and continue booting
        UBOOT_ERROR("FAIL to read mmap_filename\n");
    }
    else
    {
        if (!strstr(mmap_filename, " ") && !strstr(mmap_filename, ";"))
        {
            if (snprintf(buf, MAX_MMAP_FILENAME_LEN, "mmap_filename=%s", mmap_filename) < 0)
            {
                UBOOT_ERROR("FAIL to construct mmap_filename\n");
            }
            else
            {
                if (add_bootargs("mmap_filename", buf, 0))
                {
                    UBOOT_ERROR("FAIL to add mmap_filename to bootargs\n");
                }
            }
        }
    }

    return 0;
}

U_BOOT_CMD(
    propagate_mmap_filename,    1,    1,     do_propagate_mmap_filename,
    "U-Boot sets mmap_filename to bootargs",
    "command: propagate_mmap_filename\n"
);

#define VALID_THRESHOLD     62
#define ADC_CHANNEL_POWER   1
int do_cust_upgrade_check(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct udevice *dev, *normal_dev;
	unsigned int data;
	int ret, uV;
	char command[64] = {0};
/*
	if (get_boot_mode_flag() != EN_BOOT_MODE_NORMAL)
	{
		printf("boot_mode 0x%x, non normal mode, skip power keypad check\n", get_boot_mode_flag());
		return CMD_RET_SUCCESS;
	}
*/
#if defined(CONFIG_MTK_PM)
    if ( pm_get_boot_reason() != PM_BR_AC ) {
        printf("Reason 0x%x ,Only AC ON check power keypad!\n", pm_get_boot_reason());
        return 0;
    }
#endif

	ret = uclass_first_device_err(UCLASS_ADC, &dev);
	if (ret) {
		printf("No available ADC device\n");
		return CMD_RET_FAILURE;
	}

	do {
		UBOOT_INFO("adc device : %s\n", dev->name);
		normal_dev = dev;

		ret = uclass_next_device(&dev);
		if (ret)
			return CMD_RET_FAILURE;
	} while (dev);

	ret = adc_channel_single_shot(normal_dev->name, ADC_CHANNEL_POWER, &data);
	if (ret) {
		printf("Error getting single shot for device %s channel %d\n",
		       normal_dev->name, ADC_CHANNEL_POWER);
		return CMD_RET_FAILURE;
	}

	if (!adc_raw_to_uV(normal_dev, data, &uV))
		UBOOT_INFO("%u, %d uV\n", data, uV);
	else
		UBOOT_INFO("%u\n", data);

	if(data < VALID_THRESHOLD)
	{
		snprintf(command, sizeof(command), "mtkupgrade usb %s", ENV_CUSTOMER_PKG_PREFIX);
		UBOOT_INFO("power key press, run upgrade command:%s\n", command);
		if( 0 != run_command(command, 0))
		{
			UBOOT_INFO("uboot wipe user data\n");
			run_command("wipeuserdata", 0);
			run_command("reset", 0);
		}
	}else{
		UBOOT_INFO("power key not press, dont run upgrade\n");
	}

    return 0;
}

U_BOOT_CMD(
    cust_upgrade,    1,    1,     do_cust_upgrade_check,
    "customer upgrade check command",
    "command: cust_upgrade\n"
);
/*
 * unbalanced dram: set "kernelcore" to locate high bandwidth region.
 * balanced dram: no need.
 */
extern unsigned long long get_dram_size(void);
int do_setup_kernelcore_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
#ifdef CONFIG_SETUP_KERNEL_CORE_SIZE
#define MAX_KERNELCORE_LEN                 (20)
#define MAX_KERNELCORE_BUF_LEN             (30)
#define IN_KERNEL_RESERVED         (0x08000000)
#define WIDE_LENGTH                (0x80000000)
	static unsigned long long dram_size = 1;
	unsigned long long kernel_start = 0;
	char buf[MAX_BUF_LEN] = {0};
	int size_mb = 0;
	int ret = 0;

	UBOOT_DEBUG("do_setup_kernelcore_size\n");

	ret = get_kernel_start(&kernel_start);
	if (ret < 0) {
		UBOOT_DEBUG("failed to get kernel_start\n");
		return 0;
	}

	dram_size = get_dram_size();
	UBOOT_DEBUG("dram_size: 0x%llx, kernel_start: 0x%llx\n", dram_size, kernel_start);

	/* 5879 3G */
	if (MT5879 == romtbl_get_chip_id_info() && dram_size == SIZE_3G)
	{
		size_mb = (WIDE_LENGTH - IN_KERNEL_RESERVED - kernel_start) / SIZE_1M;
		UBOOT_DEBUG("#################### size_mb: %d\n", size_mb);
	}
	else
	{
		UBOOT_DEBUG("balanced dram, no need kernelcore setting\n");
		return 0;
	}

	if (size_mb != 0)
	{
		ret = snprintf(buf, MAX_KERNELCORE_BUF_LEN, "kernelcore=%dM", size_mb);
		if (ret < 0)
		{
			UBOOT_ERROR("FAIL to construct kernelcore\n");
			return -1;
		}

		ret = add_bootargs("kernelcore", buf, 0);
		if (ret < 0)
		{
			UBOOT_ERROR("FAIL to add kernelcore to bootargs\n");
			return -1;
		}

		UBOOT_DEBUG("unbalanced dram, set %s\n", buf);
		return 0;
	}

	return -1;
#else
	return 0;
#endif
}

U_BOOT_CMD(
    setup_kernelcore_size,    1,    1,     do_setup_kernelcore_size,
    "U-Boot sets kernelcore to bootargs",
    "command: setup_kernelcore_size\n"
);

#ifdef CONFIG_GPIO_DEFAULT_FROM_INI
int do_gpio_default_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    int ret;

    ret = gpio_default_set();
    if (ret != 0)
    {
        UBOOT_DEBUG("Do gpio default set failure\n");
        return -1;
    }

    return 0;
}

U_BOOT_CMD(
    gpiodefault,    1,    1,     do_gpio_default_set,
    "Mediatek load gpio default set command",
    "command: gpiodefault\n"
);
#endif
