aboutsummaryrefslogtreecommitdiff
path: root/drivers/meson/gxl/crypto/sha_dma.c
blob: a969dea74c50bff8a13f3fad600f3f1c85a8f8f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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 31u
#define ASD_DESC_OWNER_MASK 0x1u
#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, 1u);
	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);
}