#ifndef _UFS_EXYNOS_FMP_H_
#define _UFS_EXYNOS_FMP_H_

#define FMP_DRV_VERSION "4.0.0"

/* FMP IDs (second or third parameter to FMP/SMU Ctrls) */
#define FMP_EMBEDDED			0
#define FMP_UFSCARD			1
#define FMP_SDCARD			2

/* SMU commands (second parameter to SMC_CMD_SMU) */
#define SMU_INIT			0
#define SMU_SET				1
#define SMU_ABORT			2

/* Fourth parameter to SMC_CMD_FMP_SECURITY */
#define CFG_DESCTYPE_0			0
#define CFG_DESCTYPE_3			3

/* Fourth parameter to SMC_CMD_FMP_KW_MODE */
#define WAP0_NS				(1 << 8)
#define UNWRAP_EN			(0 << 4)
#define UNWRAP_BYPASS			(1 << 4)
#define SWKEY_MODE			0
#define SECUREKEY_MODE			1

/* Fourth parameter to SMC_CMD_FMP_KW_INDATASWAP */
#define RAW_FILEKEY_WORDSWAP            (1 << 22)
#define RAW_TWEAKKEY_WORDSWAP           (1 << 21)
#define PBK_WORDSWAP                    (1 << 20)
#define IV_WORDSWAP                     (1 << 19)
#define TAG_WORDSWAP                    (1 << 18)
#define SECURE_FILEKEY_WORDSWAP         (1 << 17)
#define SECURE_TWEAKKEY_WORDSWAP        (1 << 16)
#define RAW_FILEKEY_BYTESWAP            (1 << 6)
#define RAW_TWEAKKEY_BYTESWAP           (1 << 5)
#define PBK_BYTESWAP                    (1 << 4)
#define IV_BYTESWAP                     (1 << 3)
#define TAG_BYTESWAP                    (1 << 2)
#define SECURE_FILEKEY_BYTESWAP         (1 << 1)
#define SECURE_TWEAKKEY_BYTESWAP        (1 << 0)

/* Advertise crypto quirks to ufshcd-core. */
#ifdef CONFIG_KEYS_IN_PRDT
#define UFSHCD_QUIRK_FMP_MODE_SPECIFIC	UFSHCD_QUIRK_CUSTOM_KEYSLOT_MANAGER |\
					UFSHCD_QUIRK_KEYS_IN_PRDT
#endif

#ifdef CONFIG_HW_KEYS_IN_CUSTOM_KEYSLOT
#define UFSHCD_QUIRK_FMP_MODE_SPECIFIC	UFSHCD_QUIRK_CUSTOM_KEYSLOT_MANAGER
#endif

#ifdef CONFIG_KEYS_IN_CUSTOM_KEYSLOT
#define UFSHCD_QUIRK_FMP_MODE_SPECIFIC	UFSHCD_QUIRK_CUSTOM_KEYSLOT_MANAGER
#endif

#ifdef CONFIG_SOC_EXYNOS2100
#define UFSHCD_QUIRK_FMP_SOC_SPECIFIC UFSHCD_QUIRK_BROKEN_CRYPTO_ENABLE
#else
#define UFSHCD_QUIRK_FMP_SOC_SPECIFIC 0
#endif

enum fmp_crypto_algo_mode {
	FMP_BYPASS_MODE = 0,
	FMP_ALGO_MODE_AES_CBC = 1,
	FMP_ALGO_MODE_AES_XTS = 2,
};

#define FMP_DATA_UNIT_SIZE 4096

struct fmp_sg_entry {
	/* The first four fields correspond to those of ufshcd_sg_entry. */
	__le32 des0;
	__le32 des1;
	__le32 des2;
	/*
	 * The algorithm and key length are configured in the high bits of des3,
	 * whose low bits already contain ufshcd_sg_entry::size.
	 */
	__le32 des3;
#define FKL			(1 << 26)
#define SET_KEYLEN(ent, v)	((ent)->des3 |= cpu_to_le32(v))
#define SET_FAS(ent, v)		((ent)->des3 |= cpu_to_le32((v) << 28))

	/* The IV with all bytes reversed */
	__be32 file_iv[4];

	/*
	 * The key with all bytes reversed.  For XTS, the two halves of the key
	 * are given separately and are byte-reversed separately.
	 */
	__be32 file_enckey[8];
	__be32 file_twkey[8];

	/* Not used */
	__be32 disk_iv[4];
	__le32 reserved[4];
};

/* Number of custom keyslots */
/* 0-14 keylots: keyslot for crypto io, 15: reserved keyslot for FIPS */
#define UFS_KEYSLOTS	16

#ifdef CONFIG_EXYNOS_FMP_FIPS
#define FIPS_KEYSLOT	1
#else
#define FIPS_KEYSLOT	0
#endif

#define NUM_KEYSLOTS	(UFS_KEYSLOTS - FIPS_KEYSLOT)

#define AES_256_XTS_KEY_SIZE		64
#define SECRET_SIZE			32
#define AES_GCM_TAG_SIZE		16
#define AES_256_XTS_TWK_OFFSET		8
#define HW_WRAPPED_KEY_TAG_OFFSET	16
#define HW_WRAPPED_KEY_SECRET_OFFSET	80

/* UFSHCD register map  */
#define CRYPTOCFG	0x0440
/* 0-CRYPTOCFG - CFGE_CAPIDX_DUSIZE */
union exynos_ufs_crypto_cfg_entry {
	__le32 reg_val;
	struct {
		u8 data_unit_size;
		u8 crypto_cap_idx;
		u8 reserved_1;
		u8 config_enable;
	};
};

struct exynos_fmp {
	u8 valid_check;
};

/* FMP register map  */
#define FMP_REGS	38

#define UFSPRCTRL	0x000
#define UFSPRSTAT0	0x008
#define UFSPRSTAT1	0x00C
#define UFSPRSECURITY0	0x010
#define UFSPWCTRL	0x100
#define UFSPWSTAT0	0x108
#define UFSPWSTAT1	0x10C
#define UFSPSBEGIN0	0x2000
#define UFSPSEND0	0x2004
#define UFSPSLUN0	0x2008
#define UFSPSCTRL0	0x200C
#define UFSPSBEGIN1	0x2010
#define UFSPSEND1	0x2014
#define UFSPSLUN1	0x2018
#define UFSPSCTRL1	0x201C
#define UFSPSBEGIN2	0x2020
#define UFSPSEND2	0x2024
#define UFSPSLUN2	0x2028
#define UFSPSCTRL2	0x202C
#define UFSPSBEGIN3	0x2030
#define UFSPSEND3	0x2034
#define UFSPSLUN3	0x2038
#define UFSPSCTRL3	0x203C
#define UFSPSBEGIN4	0x2040
#define UFSPSEND4	0x2044
#define UFSPSLUN4	0x2048
#define UFSPSCTRL4	0x204C
#define UFSPSBEGIN5	0x2050
#define UFSPSEND5	0x2054
#define UFSPSLUN5	0x2058
#define UFSPSCTRL5	0x205C
#define UFSPSBEGIN6	0x2060
#define UFSPSEND6	0x2064
#define UFSPSLUN6	0x2068
#define UFSPSCTRL6	0x206C
#define UFSPSBEGIN7	0x2070
#define UFSPSEND7	0x2074
#define UFSPSLUN7	0x2078
#define UFSPSCTRL7	0x207C

#define FMP_KW_SECUREKEY	0x8000
#define FMP_KW_TAG		0x8040
#define FMP_KW_CONTROL		0xA008
#define FMP_KW_KEYVALID		0xA00C
#define FMP_KW_TAGABORT		0xA010
#define FMP_KW_PBKABORT		0xA014

#define FMP_KW_SECUREKEY_OFFSET	0x80
#define FMP_KW_TAG_OFFSET	0x80

#define EXYNOS_FMP_FIPS_KEYSLOT 0xF

/* Definition to dump fmp registers */
struct exynos_ufs_fmp_sfr_log {
        const char name[15];
        const u32 offset;
        u64 val;
};

static struct exynos_ufs_fmp_sfr_log ufs_fmp_log_sfr[FMP_REGS] = {
	{"UFSPRCTRL",		UFSPRCTRL},
	{"UFSPRSTAT0",		UFSPRSTAT0},
	{"UFSPRSTAT1",		UFSPRSTAT1},
	{"UFSPRSECURITY0",	UFSPRSECURITY0},
	{"UFSPWCTRL",		UFSPWCTRL},
	{"UFSPWSTAT0",		UFSPWSTAT0},
	{"UFSPWSTAT1",		UFSPWSTAT1},
	{"UFSPSBEGIN0",		UFSPSBEGIN0},
	{"UFSPSEND0",		UFSPSEND0},
	{"UFSPSLUN0",		UFSPSLUN0},
	{"UFSPSCTRL0",		UFSPSCTRL0},
	{"UFSPSBEGIN1",		UFSPSBEGIN1},
	{"UFSPSEND1",		UFSPSEND1},
	{"UFSPSLUN1",		UFSPSLUN1},
	{"UFSPSCTRL1",		UFSPSCTRL1},
	{"UFSPSBEGIN2",		UFSPSBEGIN2},
	{"UFSPSEND2",		UFSPSEND2},
	{"UFSPSLUN2",		UFSPSLUN2},
	{"UFSPSCTRL2",		UFSPSCTRL2},
	{"UFSPSBEGIN3",		UFSPSBEGIN3},
	{"UFSPSEND3",		UFSPSEND3},
	{"UFSPSLUN3",		UFSPSLUN3},
	{"UFSPSCTRL3",		UFSPSCTRL3},
	{"UFSPSBEGIN4",		UFSPSBEGIN4},
	{"UFSPSLUN4",		UFSPSLUN4},
	{"UFSPSCTRL4",		UFSPSCTRL4},
	{"UFSPSBEGIN5",		UFSPSBEGIN5},
	{"UFSPSEND5",		UFSPSEND5},
	{"UFSPSLUN5",		UFSPSLUN5},
	{"UFSPSCTRL5",		UFSPSCTRL5},
	{"UFSPSBEGIN6",		UFSPSBEGIN6},
	{"UFSPSEND6",		UFSPSEND6},
	{"UFSPSLUN6",		UFSPSLUN6},
	{"UFSPSCTRL6",		UFSPSCTRL6},
	{"UFSPSBEGIN7",		UFSPSBEGIN7},
	{"UFSPSEND7",		UFSPSEND7},
	{"UFSPSLUN7",		UFSPSLUN7},
	{"UFSPSCTRL7",		UFSPSCTRL7},
};

#endif /* _UFS_EXYNOS_FMP_H_ */