1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (c) 2021 Aspeed Technology Inc.
6 #include "aspeed-hace.h"
7 #include <crypto/engine.h>
9 #include <linux/dma-mapping.h>
10 #include <linux/err.h>
11 #include <linux/interrupt.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
16 #include <linux/platform_device.h>
17 #include <linux/property.h>
19 #ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG
20 #define HACE_DBG(d, fmt, ...) \
21 dev_info((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__)
23 #define HACE_DBG(d, fmt, ...) \
24 dev_dbg((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__)
27 /* HACE interrupt service routine */
28 static irqreturn_t
aspeed_hace_irq(int irq
, void *dev
)
30 struct aspeed_hace_dev
*hace_dev
= (struct aspeed_hace_dev
*)dev
;
31 struct aspeed_engine_crypto
*crypto_engine
= &hace_dev
->crypto_engine
;
32 struct aspeed_engine_hash
*hash_engine
= &hace_dev
->hash_engine
;
35 sts
= ast_hace_read(hace_dev
, ASPEED_HACE_STS
);
36 ast_hace_write(hace_dev
, sts
, ASPEED_HACE_STS
);
38 HACE_DBG(hace_dev
, "irq status: 0x%x\n", sts
);
40 if (sts
& HACE_HASH_ISR
) {
41 if (hash_engine
->flags
& CRYPTO_FLAGS_BUSY
)
42 tasklet_schedule(&hash_engine
->done_task
);
44 dev_warn(hace_dev
->dev
, "HASH no active requests.\n");
47 if (sts
& HACE_CRYPTO_ISR
) {
48 if (crypto_engine
->flags
& CRYPTO_FLAGS_BUSY
)
49 tasklet_schedule(&crypto_engine
->done_task
);
51 dev_warn(hace_dev
->dev
, "CRYPTO no active requests.\n");
57 static void aspeed_hace_crypto_done_task(unsigned long data
)
59 struct aspeed_hace_dev
*hace_dev
= (struct aspeed_hace_dev
*)data
;
60 struct aspeed_engine_crypto
*crypto_engine
= &hace_dev
->crypto_engine
;
62 crypto_engine
->resume(hace_dev
);
65 static void aspeed_hace_hash_done_task(unsigned long data
)
67 struct aspeed_hace_dev
*hace_dev
= (struct aspeed_hace_dev
*)data
;
68 struct aspeed_engine_hash
*hash_engine
= &hace_dev
->hash_engine
;
70 hash_engine
->resume(hace_dev
);
73 static void aspeed_hace_register(struct aspeed_hace_dev
*hace_dev
)
75 #ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_HASH
76 aspeed_register_hace_hash_algs(hace_dev
);
78 #ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO
79 aspeed_register_hace_crypto_algs(hace_dev
);
83 static void aspeed_hace_unregister(struct aspeed_hace_dev
*hace_dev
)
85 #ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_HASH
86 aspeed_unregister_hace_hash_algs(hace_dev
);
88 #ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO
89 aspeed_unregister_hace_crypto_algs(hace_dev
);
93 static const struct of_device_id aspeed_hace_of_matches
[] = {
94 { .compatible
= "aspeed,ast2500-hace", .data
= (void *)5, },
95 { .compatible
= "aspeed,ast2600-hace", .data
= (void *)6, },
99 static int aspeed_hace_probe(struct platform_device
*pdev
)
101 struct aspeed_engine_crypto
*crypto_engine
;
102 struct aspeed_engine_hash
*hash_engine
;
103 struct aspeed_hace_dev
*hace_dev
;
106 hace_dev
= devm_kzalloc(&pdev
->dev
, sizeof(struct aspeed_hace_dev
),
111 hace_dev
->version
= (uintptr_t)device_get_match_data(&pdev
->dev
);
112 if (!hace_dev
->version
) {
113 dev_err(&pdev
->dev
, "Failed to match hace dev id\n");
117 hace_dev
->dev
= &pdev
->dev
;
118 hash_engine
= &hace_dev
->hash_engine
;
119 crypto_engine
= &hace_dev
->crypto_engine
;
121 platform_set_drvdata(pdev
, hace_dev
);
123 hace_dev
->regs
= devm_platform_get_and_ioremap_resource(pdev
, 0, NULL
);
124 if (IS_ERR(hace_dev
->regs
))
125 return PTR_ERR(hace_dev
->regs
);
127 /* Get irq number and register it */
128 hace_dev
->irq
= platform_get_irq(pdev
, 0);
129 if (hace_dev
->irq
< 0)
132 rc
= devm_request_irq(&pdev
->dev
, hace_dev
->irq
, aspeed_hace_irq
, 0,
133 dev_name(&pdev
->dev
), hace_dev
);
135 dev_err(&pdev
->dev
, "Failed to request interrupt\n");
139 /* Get clk and enable it */
140 hace_dev
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
141 if (IS_ERR(hace_dev
->clk
)) {
142 dev_err(&pdev
->dev
, "Failed to get clk\n");
146 rc
= clk_prepare_enable(hace_dev
->clk
);
148 dev_err(&pdev
->dev
, "Failed to enable clock 0x%x\n", rc
);
152 /* Initialize crypto hardware engine structure for hash */
153 hace_dev
->crypt_engine_hash
= crypto_engine_alloc_init(hace_dev
->dev
,
155 if (!hace_dev
->crypt_engine_hash
) {
160 rc
= crypto_engine_start(hace_dev
->crypt_engine_hash
);
162 goto err_engine_hash_start
;
164 tasklet_init(&hash_engine
->done_task
, aspeed_hace_hash_done_task
,
165 (unsigned long)hace_dev
);
167 /* Initialize crypto hardware engine structure for crypto */
168 hace_dev
->crypt_engine_crypto
= crypto_engine_alloc_init(hace_dev
->dev
,
170 if (!hace_dev
->crypt_engine_crypto
) {
172 goto err_engine_hash_start
;
175 rc
= crypto_engine_start(hace_dev
->crypt_engine_crypto
);
177 goto err_engine_crypto_start
;
179 tasklet_init(&crypto_engine
->done_task
, aspeed_hace_crypto_done_task
,
180 (unsigned long)hace_dev
);
182 /* Allocate DMA buffer for hash engine input used */
183 hash_engine
->ahash_src_addr
=
184 dmam_alloc_coherent(&pdev
->dev
,
185 ASPEED_HASH_SRC_DMA_BUF_LEN
,
186 &hash_engine
->ahash_src_dma_addr
,
188 if (!hash_engine
->ahash_src_addr
) {
189 dev_err(&pdev
->dev
, "Failed to allocate dma buffer\n");
191 goto err_engine_crypto_start
;
194 /* Allocate DMA buffer for crypto engine context used */
195 crypto_engine
->cipher_ctx
=
196 dmam_alloc_coherent(&pdev
->dev
,
198 &crypto_engine
->cipher_ctx_dma
,
200 if (!crypto_engine
->cipher_ctx
) {
201 dev_err(&pdev
->dev
, "Failed to allocate cipher ctx dma\n");
203 goto err_engine_crypto_start
;
206 /* Allocate DMA buffer for crypto engine input used */
207 crypto_engine
->cipher_addr
=
208 dmam_alloc_coherent(&pdev
->dev
,
209 ASPEED_CRYPTO_SRC_DMA_BUF_LEN
,
210 &crypto_engine
->cipher_dma_addr
,
212 if (!crypto_engine
->cipher_addr
) {
213 dev_err(&pdev
->dev
, "Failed to allocate cipher addr dma\n");
215 goto err_engine_crypto_start
;
218 /* Allocate DMA buffer for crypto engine output used */
219 if (hace_dev
->version
== AST2600_VERSION
) {
220 crypto_engine
->dst_sg_addr
=
221 dmam_alloc_coherent(&pdev
->dev
,
222 ASPEED_CRYPTO_DST_DMA_BUF_LEN
,
223 &crypto_engine
->dst_sg_dma_addr
,
225 if (!crypto_engine
->dst_sg_addr
) {
226 dev_err(&pdev
->dev
, "Failed to allocate dst_sg dma\n");
228 goto err_engine_crypto_start
;
232 aspeed_hace_register(hace_dev
);
234 dev_info(&pdev
->dev
, "Aspeed Crypto Accelerator successfully registered\n");
238 err_engine_crypto_start
:
239 crypto_engine_exit(hace_dev
->crypt_engine_crypto
);
240 err_engine_hash_start
:
241 crypto_engine_exit(hace_dev
->crypt_engine_hash
);
243 clk_disable_unprepare(hace_dev
->clk
);
248 static void aspeed_hace_remove(struct platform_device
*pdev
)
250 struct aspeed_hace_dev
*hace_dev
= platform_get_drvdata(pdev
);
251 struct aspeed_engine_crypto
*crypto_engine
= &hace_dev
->crypto_engine
;
252 struct aspeed_engine_hash
*hash_engine
= &hace_dev
->hash_engine
;
254 aspeed_hace_unregister(hace_dev
);
256 crypto_engine_exit(hace_dev
->crypt_engine_hash
);
257 crypto_engine_exit(hace_dev
->crypt_engine_crypto
);
259 tasklet_kill(&hash_engine
->done_task
);
260 tasklet_kill(&crypto_engine
->done_task
);
262 clk_disable_unprepare(hace_dev
->clk
);
265 MODULE_DEVICE_TABLE(of
, aspeed_hace_of_matches
);
267 static struct platform_driver aspeed_hace_driver
= {
268 .probe
= aspeed_hace_probe
,
269 .remove
= aspeed_hace_remove
,
271 .name
= KBUILD_MODNAME
,
272 .of_match_table
= aspeed_hace_of_matches
,
276 module_platform_driver(aspeed_hace_driver
);
278 MODULE_AUTHOR("Neal Liu <neal_liu@aspeedtech.com>");
279 MODULE_DESCRIPTION("Aspeed HACE driver Crypto Accelerator");
280 MODULE_LICENSE("GPL");