/* 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 <environment.h>
#include <uuid.h>
#include <debug_impl.h>
#include <system_impl.h>
#include <utility.h>

int check_device_unique_id(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    unsigned char buf[EFUSE_BUF_SIZE];
    int i,ret;

    ret = get_device_unique_id(buf,EFUSE_BUF_SIZE);
    if(ret != 0)
    {
        UBOOT_ERROR("Get efuse did failure, please check get_efuse_did\n");
        return -1;
    }

    printf("efuse: ");
    for(i=0;i<EFUSE_BUF_SIZE;i++)
    {
        printf("0x%x ",buf[i]);
    }
    printf("\n");

    return 0;
}

U_BOOT_CMD(
    efuse,    2,    1,     check_device_unique_id,
    "Get efuse value.",
    "command: efuse\n"
);

#define CONFIGPARTITION "config"
#define RoSerialNo_Path "/RoSerial.json"
#define DEF_ROSERIAL_PREFIX "9999"
//: " => 3 offset
#define OFFSETTOVALUE 3
int add_dev_uniqueid_to_bootargs(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    unsigned char buf[EFUSE_BUF_SIZE];
    char uuid[UUID_BUF_SIZE];
    char key[ADD_BOOTARGS_KEY_SIZE];
    char set_cfg[ADD_BOOTARGS_CFG_SIZE];
    char num[EFUSE_ELEMENT_NUM];
    char *ptr;
    int i,ret;
    int snprintf_len;

    memset(uuid, 0, UUID_BUF_SIZE);
    ptr = env_get("serialno");
    if(ptr != NULL && strlen(ptr) > 0 && strlen(ptr) < UUID_BUF_SIZE)
    {
        strncat(uuid,ptr,strlen(ptr));
    }
    else
    {
        UBOOT_INFO("Serial number had not set in ENV before, get efuse id first.\n");
        memset(buf, 0, sizeof(buf));
        ret = get_device_unique_id(buf,EFUSE_BUF_SIZE);
        if(ret != 0)
        {
            UBOOT_INFO("Get efuse id failure, produce device id by random.\n");
            ret = generate_random_number(buf, EFUSE_BUF_SIZE);
            if(ret != 0)
                UBOOT_ERROR("Generate random number failure.\n");
        }

        for(i=0;i<EFUSE_BUF_SIZE;i++)
        {
            memset(num, 0, sizeof(num));
            snprintf_len = snprintf(num, sizeof(num)-1, "%02X", buf[i]);
            if (snprintf_len >= (sizeof(num)-1))
            {
                UBOOT_ERROR("The array size is too small(%d), snprintf fail '%s'\n", (int)(sizeof(num)-1), num);
                return -1;
            }
            strncat(uuid,num, UUID_BUF_SIZE-1);
        }
        env_set("serialno",uuid);
        env_save();
    }

    UBOOT_INFO("serialno=%s\n",uuid);
    memset(key, 0, ADD_BOOTARGS_KEY_SIZE);
    memset(set_cfg, 0, ADD_BOOTARGS_CFG_SIZE);
    strncpy(key,"androidboot.serialno",sizeof(key)-1);
    char * SoSerialNo = NULL;
    char * PosSerialValStart = NULL;
    char * PosSerialNoStart = NULL;
    char * PosSerialNoEnd = NULL;
    size_t RoSerialLen = 0;
    loff_t size;
    char SoSerialNo_value[ADD_BOOTARGS_CFG_SIZE] = "\0";
    SoSerialNo = (char *)read_storage_file_to_memory(CONFIGPARTITION, RoSerialNo_Path, &size);
    //ToDo Use Json Map instead.
    if (SoSerialNo != NULL) {
        PosSerialValStart = strchr(SoSerialNo, ':');
        if (PosSerialValStart != NULL){
            PosSerialNoStart = strchr(PosSerialValStart, '\"') + 1;
            if (PosSerialNoStart != NULL) {
                PosSerialNoEnd = strchr(PosSerialNoStart, '\"');
                if (PosSerialNoEnd != NULL) {
                    RoSerialLen = PosSerialNoEnd - PosSerialNoStart;
                    if (RoSerialLen < ADD_BOOTARGS_CFG_SIZE) {
                        strncpy(SoSerialNo_value, PosSerialNoStart, RoSerialLen);
                    }
                    else {
                        UBOOT_ERROR("%s size (%d) is bigger than allocated size %d\n", RoSerialNo_Path,  (int)RoSerialLen, (int)ADD_BOOTARGS_CFG_SIZE);
                    }
                }
                else {
                    UBOOT_ERROR("Cannot find end point of %s\n", RoSerialNo_Path);
                }
            }
            else {
                UBOOT_ERROR("Cannot find start point of %s\n", RoSerialNo_Path);
            }
        }
        else {
            UBOOT_ERROR("Cannot find value start for %s\n", RoSerialNo_Path);
        }
    }
    else {
        // Failed to read RoSerial.json
        UBOOT_ERROR("Failed to read %s!! Using default RoSerial value\n", RoSerialNo_Path);
    }
    if (strnlen(SoSerialNo_value, ADD_BOOTARGS_CFG_SIZE - 1) <= 0){
		strncpy(uuid, DEF_ROSERIAL_PREFIX, 4);
        UBOOT_ERROR("serial not set!! using Default value %s\n", uuid);
        snprintf(SoSerialNo_value, ADD_BOOTARGS_CFG_SIZE - 1, "%s", uuid);
    }
    printf("Get Ro Serial No %s\n", SoSerialNo_value);
    snprintf_len = snprintf(set_cfg, sizeof(set_cfg),"%s=%s",key,SoSerialNo_value);
    if (snprintf_len >= (sizeof(set_cfg)-1))
    {
        UBOOT_ERROR("The array size is too small(%d), snprintf fail '%s'\n", (int)(sizeof(set_cfg)-1), set_cfg);
        return -1;
    }
    ret = add_bootargs(key,set_cfg,0);
    if(ret == -1)
    {
        UBOOT_ERROR("Add unique id to bootargs failure\n");
        return -1;
    }
    return 0;
}

U_BOOT_CMD(
    deviceid,    2,    1,     add_dev_uniqueid_to_bootargs,
    "Add unique id to bootargs.",
    "command: deviceid\n"
);

int do_mtk_driver_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    int ret;

    ret = mtk_driver_init();
    if(ret != 0)
        UBOOT_ERROR("Mediatek driver already initial, do not initialize twice.\n");

    return 0;
}

U_BOOT_CMD(
    mtk_drv_init,    CONFIG_SYS_MAXARGS,    1,     do_mtk_driver_init,
    "Mediatek driver initialization",
    "command: mtk_drv_init\n"
);
