meson/gxl: Add support for SHA256 DMA engine

In order to configure and boot SCP, BL31 has to compute and send
the SHA-256 of the firmware data via scpi. Luckily Amlogic GXL SOC
has a DMA facility that could be used to offload SHA-256
computations. This adds basic support of this hardware SHA-256
engine.

Signed-off-by: Remi Pommarel <repk@triplefau.lt>
diff --git a/drivers/meson/gxl/crypto/sha_dma.c b/drivers/meson/gxl/crypto/sha_dma.c
new file mode 100644
index 0000000..565099c
--- /dev/null
+++ b/drivers/meson/gxl/crypto/sha_dma.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2019, Remi Pommarel <repk@triplefau.lt>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+#include <crypto/sha_dma.h>
+
+#define AML_SHA_DMA_BASE 0xc883e000
+
+#define AML_SHA_DMA_DESC (AML_SHA_DMA_BASE + 0x08)
+#define AML_SHA_DMA_STATUS (AML_SHA_DMA_BASE + 0x18)
+
+#define ASD_MODE_SHA224 0x7
+#define ASD_MODE_SHA256 0x6
+
+/* SHA DMA descriptor */
+struct asd_desc {
+	uint32_t cfg;
+	uint32_t src;
+	uint32_t dst;
+};
+#define ASD_DESC_GET(x, msk, off) (((x) >> (off)) & (msk))
+#define ASD_DESC_SET(x, v, msk, off)					\
+	((x) = ((x) & ~((msk) << (off))) | (((v) & (msk)) << (off)))
+
+#define ASD_DESC_LEN_OFF 0
+#define ASD_DESC_LEN_MASK 0x1ffff
+#define ASD_DESC_LEN(d)							\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_LEN_MASK, ASD_DESC_LEN_OFF))
+#define ASD_DESC_LEN_SET(d, v)						\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_LEN_MASK, ASD_DESC_LEN_OFF))
+
+#define ASD_DESC_IRQ_OFF 17
+#define ASD_DESC_IRQ_MASK 0x1
+#define ASD_DESC_IRQ(d)							\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_IRQ_MASK, ASD_DESC_IRQ_OFF))
+#define ASD_DESC_IRQ_SET(d, v)						\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_IRQ_MASK, ASD_DESC_IRQ_OFF))
+
+#define ASD_DESC_EOD_OFF 18
+#define ASD_DESC_EOD_MASK 0x1
+#define ASD_DESC_EOD(d)							\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_EOD_MASK, ASD_DESC_EOD_OFF))
+#define ASD_DESC_EOD_SET(d, v)						\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_EOD_MASK, ASD_DESC_EOD_OFF))
+
+#define ASD_DESC_LOOP_OFF 19
+#define ASD_DESC_LOOP_MASK 0x1
+#define ASD_DESC_LOOP(d)						\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_LOOP_MASK, ASD_DESC_LOOP_OFF))
+#define ASD_DESC_LOOP_SET(d, v)						\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_LOOP_MASK, ASD_DESC_LOOP_OFF))
+
+#define ASD_DESC_MODE_OFF 20
+#define ASD_DESC_MODE_MASK 0xf
+#define ASD_DESC_MODE(d)						\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_MODE_MASK, ASD_DESC_MODE_OFF))
+#define ASD_DESC_MODE_SET(d, v)						\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_MODE_MASK, ASD_DESC_MODE_OFF))
+
+#define ASD_DESC_BEGIN_OFF 24
+#define ASD_DESC_BEGIN_MASK 0x1
+#define ASD_DESC_BEGIN(d)						\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_BEGIN_MASK, ASD_DESC_BEGIN_OFF))
+#define ASD_DESC_BEGIN_SET(d, v)					\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_BEGIN_MASK, ASD_DESC_BEGIN_OFF))
+
+#define ASD_DESC_END_OFF 25
+#define ASD_DESC_END_MASK 0x1
+#define ASD_DESC_END(d)							\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_END_MASK, ASD_DESC_END_OFF))
+#define ASD_DESC_END_SET(d, v)						\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_END_MASK, ASD_DESC_END_OFF))
+
+#define ASD_DESC_OP_OFF 26
+#define ASD_DESC_OP_MASK 0x2
+#define ASD_DESC_OP(d)							\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_OP_MASK, ASD_DESC_OP_OFF))
+#define ASD_DESC_OP_SET(d, v)						\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_OP_MASK, ASD_DESC_OP_OFF))
+
+#define ASD_DESC_ENCONLY_OFF 28
+#define ASD_DESC_ENCONLY_MASK 0x1
+#define ASD_DESC_ENCONLY(d)						\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_ENCONLY_MASK, ASD_DESC_ENCONLY_OFF))
+#define ASD_DESC_ENCONLY_SET(d, v)					\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_ENCONLY_MASK, ASD_DESC_ENCONLY_OFF))
+
+#define ASD_DESC_BLOCK_OFF 29
+#define ASD_DESC_BLOCK_MASK 0x1
+#define ASD_DESC_BLOCK(d)						\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_BLOCK_MASK, ASD_DESC_BLOCK_OFF))
+#define ASD_DESC_BLOCK_SET(d, v)					\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_BLOCK_MASK, ASD_DESC_BLOCK_OFF))
+
+#define ASD_DESC_ERR_OFF 30
+#define ASD_DESC_ERR_MASK 0x1
+#define ASD_DESC_ERR(d)						\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_ERR_MASK, ASD_DESC_ERR_OFF))
+#define ASD_DESC_ERR_SET(d, v)					\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_ERR_MASK, ASD_DESC_ERR_OFF))
+
+#define ASD_DESC_OWNER_OFF 31
+#define ASD_DESC_OWNER_MASK 0x1
+#define ASD_DESC_OWNER(d)					\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_OWNER_MASK, ASD_DESC_OWNER_OFF))
+#define ASD_DESC_OWNER_SET(d, v)				\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_OWNER_MASK, ASD_DESC_OWNER_OFF))
+
+static void asd_compute_sha(struct asd_ctx *ctx, void *data, size_t len,
+		int finalize)
+{
+	/* Make it cache line size aligned ? */
+	struct asd_desc desc = {
+		.src = (uint32_t)(uintptr_t)data,
+		.dst = (uint32_t)(uintptr_t)ctx->digest,
+	};
+
+	/* Check data address is 32bit compatible */
+	assert((uintptr_t)data == (uintptr_t)desc.src);
+	assert((uintptr_t)ctx->digest == (uintptr_t)desc.dst);
+	assert((uintptr_t)&desc == (uintptr_t)&desc);
+
+	ASD_DESC_LEN_SET(&desc, len);
+	ASD_DESC_OWNER_SET(&desc, 1);
+	ASD_DESC_ENCONLY_SET(&desc, 1);
+	ASD_DESC_EOD_SET(&desc, 1);
+	if (ctx->started == 0) {
+		ASD_DESC_BEGIN_SET(&desc, 1);
+		ctx->started = 1;
+	}
+	if (finalize) {
+		ASD_DESC_END_SET(&desc, 1);
+		ctx->started = 0;
+	}
+	if (ctx->mode == ASM_SHA224)
+		ASD_DESC_MODE_SET(&desc, ASD_MODE_SHA224);
+	else
+		ASD_DESC_MODE_SET(&desc, ASD_MODE_SHA256);
+
+	flush_dcache_range((uintptr_t)&desc, sizeof(desc));
+	flush_dcache_range((uintptr_t)data, len);
+
+	mmio_write_32(AML_SHA_DMA_STATUS, 0xf);
+	mmio_write_32(AML_SHA_DMA_DESC, ((uintptr_t)&desc) | 2);
+	while (mmio_read_32(AML_SHA_DMA_STATUS) == 0)
+		continue;
+	flush_dcache_range((uintptr_t)ctx->digest, SHA256_HASHSZ);
+}
+
+void asd_sha_update(struct asd_ctx *ctx, void *data, size_t len)
+{
+	size_t nr;
+
+	if (ctx->blocksz) {
+		nr = MIN(len, SHA256_BLOCKSZ - ctx->blocksz);
+		memcpy(ctx->block + ctx->blocksz, data, nr);
+		ctx->blocksz += nr;
+		len -= nr;
+		data += nr;
+	}
+
+	if (ctx->blocksz == SHA256_BLOCKSZ) {
+		asd_compute_sha(ctx, ctx->block, SHA256_BLOCKSZ, 0);
+		ctx->blocksz = 0;
+	}
+
+	asd_compute_sha(ctx, data, len & ~(SHA256_BLOCKSZ - 1), 0);
+	data += len & ~(SHA256_BLOCKSZ - 1);
+
+	if (len & (SHA256_BLOCKSZ - 1)) {
+		nr = len & (SHA256_BLOCKSZ - 1);
+		memcpy(ctx->block + ctx->blocksz, data, nr);
+		ctx->blocksz += nr;
+	}
+}
+
+void asd_sha_finalize(struct asd_ctx *ctx)
+{
+	asd_compute_sha(ctx, ctx->block, ctx->blocksz, 1);
+}
diff --git a/include/drivers/meson/gxl/crypto/sha_dma.h b/include/drivers/meson/gxl/crypto/sha_dma.h
new file mode 100644
index 0000000..52129a6
--- /dev/null
+++ b/include/drivers/meson/gxl/crypto/sha_dma.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019, Remi Pommarel <repk@triplefau.lt>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef SHA_DMA_H
+#define SHA_DMA_H
+
+#define SHA256_HASHSZ 32
+#define SHA256_BLOCKSZ 0x40
+
+enum ASD_MODE {
+	ASM_INVAL,
+	ASM_SHA256,
+	ASM_SHA224,
+};
+
+struct asd_ctx {
+	uint8_t digest[SHA256_HASHSZ];
+	uint8_t block[SHA256_BLOCKSZ];
+	size_t blocksz;
+	enum ASD_MODE mode;
+	uint8_t started;
+};
+
+static inline void asd_sha_init(struct asd_ctx *ctx, enum ASD_MODE mode)
+{
+	ctx->started = 0;
+	ctx->mode = mode;
+	ctx->blocksz = 0;
+}
+
+void asd_sha_update(struct asd_ctx *ctx, void *data, size_t len);
+void asd_sha_finalize(struct asd_ctx *ctx);
+
+#endif
diff --git a/plat/meson/gxl/platform.mk b/plat/meson/gxl/platform.mk
index 7437dfd..de61929 100644
--- a/plat/meson/gxl/platform.mk
+++ b/plat/meson/gxl/platform.mk
@@ -7,6 +7,7 @@
 include lib/xlat_tables_v2/xlat_tables.mk
 
 PLAT_INCLUDES		:=	-Iinclude/drivers/meson/		\
+				-Iinclude/drivers/meson/gxl		\
 				-Iplat/meson/gxl/include
 
 GXBB_GIC_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
@@ -22,13 +23,14 @@
 BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
 				plat/common/plat_psci_common.c		\
 				plat/meson/gxl/aarch64/gxl_helpers.S	\
-				plat/meson/gxl/gxl_bl31_setup.c	\
+				plat/meson/gxl/gxl_bl31_setup.c		\
 				plat/meson/gxl/gxl_efuse.c		\
 				plat/meson/gxl/gxl_mhu.c		\
-				plat/meson/gxl/gxl_pm.c		\
+				plat/meson/gxl/gxl_pm.c			\
 				plat/meson/gxl/gxl_scpi.c		\
 				plat/meson/gxl/gxl_sip_svc.c		\
 				plat/meson/gxl/gxl_thermal.c		\
+				drivers/meson/gxl/crypto/sha_dma.c	\
 				${GXBB_GIC_SOURCES}
 
 # Tune compiler for Cortex-A53