/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef __ASPEED_HACE_H__
#define __ASPEED_HACE_H__

#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/fips.h>
#include <linux/dma-mapping.h>
#include <crypto/aes.h>
#include <crypto/des.h>
#include <crypto/scatterwalk.h>
#include <crypto/internal/aead.h>
#include <crypto/internal/akcipher.h>
#include <crypto/internal/des.h>
#include <crypto/internal/hash.h>
#include <crypto/internal/kpp.h>
#include <crypto/internal/skcipher.h>
#include <crypto/algapi.h>
#include <crypto/engine.h>
#include <crypto/hmac.h>
#include <crypto/sha1.h>
#include <crypto/sha2.h>

/*****************************
 *                           *
 * HACE register definitions *
 *                           *
 * ***************************/
#define ASPEED_HACE_SRC			0x00	/* Crypto Data Source Base Address Register */
#define ASPEED_HACE_DEST		0x04	/* Crypto Data Destination Base Address Register */
#define ASPEED_HACE_CONTEXT		0x08	/* Crypto Context Buffer Base Address Register */
#define ASPEED_HACE_DATA_LEN		0x0C	/* Crypto Data Length Register */
#define ASPEED_HACE_CMD			0x10	/* Crypto Engine Command Register */

/* G5 */
#define ASPEED_HACE_TAG			0x18	/* HACE Tag Register */
/* G6 */
#define ASPEED_HACE_GCM_ADD_LEN		0x14	/* Crypto AES-GCM Additional Data Length Register */
#define ASPEED_HACE_GCM_TAG_BASE_ADDR	0x18	/* Crypto AES-GCM Tag Write Buff Base Address Reg */

#define ASPEED_HACE_STS			0x1C	/* HACE Status Register */

#define ASPEED_HACE_HASH_SRC		0x20	/* Hash Data Source Base Address Register */
#define ASPEED_HACE_HASH_DIGEST_BUFF	0x24	/* Hash Digest Write Buffer Base Address Register */
#define ASPEED_HACE_HASH_KEY_BUFF	0x28	/* Hash HMAC Key Buffer Base Address Register */
#define ASPEED_HACE_HASH_DATA_LEN	0x2C	/* Hash Data Length Register */
#define ASPEED_HACE_HASH_CMD		0x30	/* Hash Engine Command Register */

/* crypto cmd */
#define  HACE_CMD_SINGLE_DES		0
#define  HACE_CMD_TRIPLE_DES		BIT(17)
#define  HACE_CMD_AES_SELECT		0
#define  HACE_CMD_DES_SELECT		BIT(16)
#define  HACE_CMD_ISR_EN		BIT(12)
#define  HACE_CMD_CONTEXT_SAVE_ENABLE	(0)
#define  HACE_CMD_CONTEXT_SAVE_DISABLE	BIT(9)
#define  HACE_CMD_AES			(0)
#define  HACE_CMD_DES			(0)
#define  HACE_CMD_RC4			BIT(8)
#define  HACE_CMD_DECRYPT		(0)
#define  HACE_CMD_ENCRYPT		BIT(7)

#define  HACE_CMD_ECB			(0x0 << 4)
#define  HACE_CMD_CBC			(0x1 << 4)
#define  HACE_CMD_CFB			(0x2 << 4)
#define  HACE_CMD_OFB			(0x3 << 4)
#define  HACE_CMD_CTR			(0x4 << 4)
#define  HACE_CMD_OP_MODE_MASK		(0x7 << 4)

#define  HACE_CMD_AES128		(0x0 << 2)
#define  HACE_CMD_AES192		(0x1 << 2)
#define  HACE_CMD_AES256		(0x2 << 2)
#define  HACE_CMD_OP_CASCADE		(0x3)
#define  HACE_CMD_OP_INDEPENDENT	(0x1)

/* G5 */
#define  HACE_CMD_RI_WO_DATA_ENABLE	(0)
#define  HACE_CMD_RI_WO_DATA_DISABLE	BIT(11)
#define  HACE_CMD_CONTEXT_LOAD_ENABLE	(0)
#define  HACE_CMD_CONTEXT_LOAD_DISABLE	BIT(10)
/* G6 */
#define  HACE_CMD_AES_KEY_FROM_OTP	BIT(24)
#define  HACE_CMD_GHASH_TAG_XOR_EN	BIT(23)
#define  HACE_CMD_GHASH_PAD_LEN_INV	BIT(22)
#define  HACE_CMD_GCM_TAG_ADDR_SEL	BIT(21)
#define  HACE_CMD_MBUS_REQ_SYNC_EN	BIT(20)
#define  HACE_CMD_DES_SG_CTRL		BIT(19)
#define  HACE_CMD_SRC_SG_CTRL		BIT(18)
#define  HACE_CMD_CTR_IV_AES_96		(0x1 << 14)
#define  HACE_CMD_CTR_IV_DES_32		(0x1 << 14)
#define  HACE_CMD_CTR_IV_AES_64		(0x2 << 14)
#define  HACE_CMD_CTR_IV_AES_32		(0x3 << 14)
#define  HACE_CMD_AES_KEY_HW_EXP	BIT(13)
#define  HACE_CMD_GCM			(0x5 << 4)

/* interrupt status reg */
#define  HACE_CRYPTO_ISR		BIT(12)
#define  HACE_HASH_ISR			BIT(9)
#define  HACE_HASH_BUSY			BIT(0)

/* hash cmd reg */
#define  HASH_CMD_MBUS_REQ_SYNC_EN	BIT(20)
#define  HASH_CMD_HASH_SRC_SG_CTRL	BIT(18)
#define  HASH_CMD_SHA512_224		(0x3 << 10)
#define  HASH_CMD_SHA512_256		(0x2 << 10)
#define  HASH_CMD_SHA384		(0x1 << 10)
#define  HASH_CMD_SHA512		(0)
#define  HASH_CMD_INT_ENABLE		BIT(9)
#define  HASH_CMD_HMAC			(0x1 << 7)
#define  HASH_CMD_ACC_MODE		(0x2 << 7)
#define  HASH_CMD_HMAC_KEY		(0x3 << 7)
#define  HASH_CMD_SHA1			(0x2 << 4)
#define  HASH_CMD_SHA224		(0x4 << 4)
#define  HASH_CMD_SHA256		(0x5 << 4)
#define  HASH_CMD_SHA512_SER		(0x6 << 4)
#define  HASH_CMD_SHA_SWAP		(0x2 << 2)

#define HASH_SG_LAST_LIST		BIT(31)

#define CRYPTO_FLAGS_BUSY		BIT(1)

#define SHA_OP_UPDATE			1
#define SHA_OP_FINAL			2

#define SHA_FLAGS_SHA1			BIT(0)
#define SHA_FLAGS_SHA224		BIT(1)
#define SHA_FLAGS_SHA256		BIT(2)
#define SHA_FLAGS_SHA384		BIT(3)
#define SHA_FLAGS_SHA512		BIT(4)
#define SHA_FLAGS_SHA512_224		BIT(5)
#define SHA_FLAGS_SHA512_256		BIT(6)
#define SHA_FLAGS_HMAC			BIT(8)
#define SHA_FLAGS_FINUP			BIT(9)
#define SHA_FLAGS_MASK			(0xff)

#define ASPEED_CRYPTO_SRC_DMA_BUF_LEN	0xa000
#define ASPEED_CRYPTO_DST_DMA_BUF_LEN	0xa000
#define ASPEED_CRYPTO_GCM_TAG_OFFSET	0x9ff0
#define ASPEED_HASH_SRC_DMA_BUF_LEN	0xa000
#define ASPEED_HASH_QUEUE_LENGTH	50

#define HACE_CMD_IV_REQUIRE		(HACE_CMD_CBC | HACE_CMD_CFB | \
					 HACE_CMD_OFB | HACE_CMD_CTR)

struct aspeed_hace_dev;

typedef int (*aspeed_hace_fn_t)(struct aspeed_hace_dev *);

struct aspeed_sg_list {
	__le32 len;
	__le32 phy_addr;
};

struct aspeed_engine_hash {
	struct tasklet_struct		done_task;
	unsigned long			flags;
	struct ahash_request		*req;

	/* input buffer */
	void				*ahash_src_addr;
	dma_addr_t			ahash_src_dma_addr;

	dma_addr_t			src_dma;
	dma_addr_t			digest_dma;

	size_t				src_length;

	/* callback func */
	aspeed_hace_fn_t		resume;
	aspeed_hace_fn_t		dma_prepare;
};

struct aspeed_sha_hmac_ctx {
	struct crypto_shash *shash;
	u8 ipad[SHA512_BLOCK_SIZE];
	u8 opad[SHA512_BLOCK_SIZE];
};

struct aspeed_sham_ctx {
	struct crypto_engine_ctx	enginectx;

	struct aspeed_hace_dev		*hace_dev;
	unsigned long			flags;	/* hmac flag */

	struct aspeed_sha_hmac_ctx	base[];
};

struct aspeed_sham_reqctx {
	unsigned long		flags;		/* final update flag should no use*/
	unsigned long		op;		/* final or update */
	u32			cmd;		/* trigger cmd */

	/* walk state */
	struct scatterlist	*src_sg;
	int			src_nents;
	unsigned int		offset;		/* offset in current sg */
	unsigned int		total;		/* per update length */

	size_t			digsize;
	size_t			block_size;
	size_t			ivsize;
	const __be32		*sha_iv;

	/* remain data buffer */
	u8			buffer[SHA512_BLOCK_SIZE * 2];
	dma_addr_t		buffer_dma_addr;
	size_t			bufcnt;		/* buffer counter */

	/* output buffer */
	u8			digest[SHA512_DIGEST_SIZE] __aligned(64);
	dma_addr_t		digest_dma_addr;
	u64			digcnt[2];
};

struct aspeed_engine_crypto {
	struct tasklet_struct		done_task;
	unsigned long			flags;
	struct skcipher_request		*req;

	/* context buffer */
	void				*cipher_ctx;
	dma_addr_t			cipher_ctx_dma;

	/* input buffer, could be single/scatter-gather lists */
	void				*cipher_addr;
	dma_addr_t			cipher_dma_addr;

	/* output buffer, only used in scatter-gather lists */
	void				*dst_sg_addr;
	dma_addr_t			dst_sg_dma_addr;

	/* callback func */
	aspeed_hace_fn_t		resume;
};

struct aspeed_cipher_ctx {
	struct crypto_engine_ctx	enginectx;

	struct aspeed_hace_dev		*hace_dev;
	int				key_len;
	u8				key[AES_MAX_KEYLENGTH];

	/* callback func */
	aspeed_hace_fn_t		start;

	struct crypto_skcipher          *fallback_tfm;
};

struct aspeed_cipher_reqctx {
	int enc_cmd;
	int src_nents;
	int dst_nents;

	struct skcipher_request         fallback_req;   /* keep at the end */
};

struct aspeed_hace_dev {
	void __iomem			*regs;
	struct device			*dev;
	int				irq;
	struct clk			*clk;
	unsigned long			version;

	struct crypto_engine		*crypt_engine_hash;
	struct crypto_engine		*crypt_engine_crypto;

	struct aspeed_engine_hash	hash_engine;
	struct aspeed_engine_crypto	crypto_engine;
};

struct aspeed_hace_alg {
	struct aspeed_hace_dev		*hace_dev;

	const char			*alg_base;

	union {
		struct skcipher_alg	skcipher;
		struct ahash_alg	ahash;
	} alg;
};

enum aspeed_version {
	AST2500_VERSION = 5,
	AST2600_VERSION
};

#define ast_hace_write(hace, val, offset)	\
	writel((val), (hace)->regs + (offset))
#define ast_hace_read(hace, offset)		\
	readl((hace)->regs + (offset))

void aspeed_register_hace_hash_algs(struct aspeed_hace_dev *hace_dev);
void aspeed_unregister_hace_hash_algs(struct aspeed_hace_dev *hace_dev);
void aspeed_register_hace_crypto_algs(struct aspeed_hace_dev *hace_dev);
void aspeed_unregister_hace_crypto_algs(struct aspeed_hace_dev *hace_dev);

#endif
