/*
 * Copyright 2020,2021 Sony Home Entertainment & Sound Products Inc.
 */
#include <common.h>
#include <command.h>
#include <console.h>
#include <fs.h>

#define MAX_PATH_LEN	1024
#define MAX_BID_NUM	15

#if DTB_SWITCH_BY_MODELID
#include <nvp.h>
#define MAX_MARK_LEN	8
#define NVP_MID_LEN	4
#define BID_PART_STR	"-%d"
#define DELIMITER1	'-'
#define DELIMITER2	'_'
#endif

DECLARE_GLOBAL_DATA_PTR;

#if DTB_SWITCH_BY_MODELID
static void to_lower(char *txt)
{
	while (*txt) {
		if (*txt >= 'A' && *txt <= 'Z')
			*txt += 0x20;
		txt++;
	}
}

static int check_asc(char *txt)
{
	while (*txt) {
		if (*txt < 0x20 || *txt > 0x7E)
			return -1;
		txt++;
	}
	return 0;
}
#endif
static int do_dtbname (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	char fdt_name[MAX_PATH_LEN];
	long bid = MAX_BID_NUM;
#if DTB_SWITCH_BY_MODELID
	char fdt_base[MAX_PATH_LEN];
	char mid[NVP_MID_LEN + 1];
	unsigned int modelid = 0;
	char *s1, *s2, *s3;
	size_t clen;
	bool usemid = false;
	long brv;
	int ret;
#endif

	if (argc < 4)
		return cmd_usage(cmdtp);

	if (argc > 4) {
		bid = simple_strtol(argv[4], NULL, 10);
		if (bid < 0 || bid > MAX_BID_NUM) {
			printf("beyond the board-id range: board-id=%ld\n", bid);
			printf("Try with maximum board-id\n");
			bid = MAX_BID_NUM;
		}
	}

#if DTB_SWITCH_BY_MODELID
	if (icx_nvp_get_modelid(&modelid, NVP_MID_LEN) < 0) {
		printf("Unable to get modelid from nvp\n");
	} else if (modelid == 0 || modelid == -1) {
		printf("modelid is not set in nvp\n");
	} else {
		printf("modelid=0x%08x\n", modelid);
		mid[0] = (char)((modelid >> 24) & 0xff);
		mid[1] = (char)((modelid >> 16) & 0xff);
		mid[2] = (char)((modelid >> 8) & 0xff);
		mid[3] = (char)(modelid & 0xff);
		mid[4] = '\0';
		if (mid[0] == 0x0) {
			printf("modelid is empty\n");
			goto nonmid;
		}
		if (check_asc(mid)) {
			printf("modelid contains non-ascii characters\n");
			goto nonmid;
		}

		s2 = strstr(argv[3], BID_PART_STR);
		if (!s2)
			goto nonmid;
		for (s1 = s2 - 1, s3 = NULL; s1 > argv[3]; s1--) {
			if (*s1 == DELIMITER1 || *s1 == DELIMITER2) {
				s3 = s1 + 1;
				break;
			}
		}
		if (s3) {
			clen = (size_t)(s3 - argv[3]);
			strncpy(fdt_base, argv[3], clen);
			fdt_base[clen] = '\0';
			to_lower(mid);
			strncat(fdt_base, mid, MAX_PATH_LEN);
			strncat(fdt_base, s2, MAX_PATH_LEN);
			usemid = true;
		} else {
			printf("modelid cannot detect from base-filename\n");
		}
	}
nonmid:
	brv = bid;
	while (brv >= 0) {
		if (usemid)
			ret = snprintf(fdt_name, MAX_PATH_LEN, fdt_base, brv);
		else
			ret = snprintf(fdt_name, MAX_PATH_LEN, argv[3], brv);

		if (ret > 0) {
			if (file_exists(argv[1], argv[2], fdt_name, FS_TYPE_ANY))
				break;
			else
				printf("not found: %s\n", fdt_name);
		} else {
			printf("Does not include board-id in filename\n");
			strncpy(fdt_name, argv[3], MAX_PATH_LEN);
			break;
		}

		if (usemid && brv == 0) {
			usemid = false;
			brv = bid;
		} else {
			brv--;
		}
	}
#else
	do {
		if (snprintf(fdt_name, MAX_PATH_LEN, argv[3], bid) > 0) {
			if (file_exists(argv[1], argv[2], fdt_name, FS_TYPE_ANY))
				break;
			else
				printf("not found: %s\n", fdt_name);
		} else {
			printf("Does not include board-id in filename\n");
			strncpy(fdt_name, argv[3], MAX_PATH_LEN);
			break;
		}
	} while ((bid--) > 0);
#endif

	env_set("fdt_file", fdt_name);
	printf("fdt_file=%s\n", fdt_name);

	return CMD_RET_SUCCESS;
}
U_BOOT_CMD(
	dtbname,	5,	1,	do_dtbname,
	"Make DTB file name by board-id",
	"<interface> <dev[:part]> <base-filename> <board-id>"
);
