1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2021 Aspeed Technology Inc. 4 */ 5 6 #include "aspeed-hace.h" 7 #include <crypto/engine.h> 8 #include <linux/clk.h> 9 #include <linux/dma-mapping.h> 10 #include <linux/err.h> 11 #include <linux/interrupt.h> 12 #include <linux/io.h> 13 #include <linux/kernel.h> 14 #include <linux/module.h> 15 #include <linux/of.h> 16 #include <linux/platform_device.h> 17 #include <linux/property.h> 18 19 #ifdef CONFIG_CRYPTO_DEV_ASPEED_DEBUG 20 #define HACE_DBG(d, fmt, ...) \ 21 dev_info((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) 22 #else 23 #define HACE_DBG(d, fmt, ...) \ 24 dev_dbg((d)->dev, "%s() " fmt, __func__, ##__VA_ARGS__) 25 #endif 26 27 /* HACE interrupt service routine */ 28 static irqreturn_t aspeed_hace_irq(int irq, void *dev) 29 { 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; 33 u32 sts; 34 35 sts = ast_hace_read(hace_dev, ASPEED_HACE_STS); 36 ast_hace_write(hace_dev, sts, ASPEED_HACE_STS); 37 38 HACE_DBG(hace_dev, "irq status: 0x%x\n", sts); 39 40 if (sts & HACE_HASH_ISR) { 41 if (hash_engine->flags & CRYPTO_FLAGS_BUSY) 42 tasklet_schedule(&hash_engine->done_task); 43 else 44 dev_warn(hace_dev->dev, "HASH no active requests.\n"); 45 } 46 47 if (sts & HACE_CRYPTO_ISR) { 48 if (crypto_engine->flags & CRYPTO_FLAGS_BUSY) 49 tasklet_schedule(&crypto_engine->done_task); 50 else 51 dev_warn(hace_dev->dev, "CRYPTO no active requests.\n"); 52 } 53 54 return IRQ_HANDLED; 55 } 56 57 static void aspeed_hace_crypto_done_task(unsigned long data) 58 { 59 struct aspeed_hace_dev *hace_dev = (struct aspeed_hace_dev *)data; 60 struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; 61 62 crypto_engine->resume(hace_dev); 63 } 64 65 static void aspeed_hace_hash_done_task(unsigned long data) 66 { 67 struct aspeed_hace_dev *hace_dev = (struct aspeed_hace_dev *)data; 68 struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine; 69 70 hash_engine->resume(hace_dev); 71 } 72 73 static void aspeed_hace_register(struct aspeed_hace_dev *hace_dev) 74 { 75 #ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_HASH 76 aspeed_register_hace_hash_algs(hace_dev); 77 #endif 78 #ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO 79 aspeed_register_hace_crypto_algs(hace_dev); 80 #endif 81 } 82 83 static void aspeed_hace_unregister(struct aspeed_hace_dev *hace_dev) 84 { 85 #ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_HASH 86 aspeed_unregister_hace_hash_algs(hace_dev); 87 #endif 88 #ifdef CONFIG_CRYPTO_DEV_ASPEED_HACE_CRYPTO 89 aspeed_unregister_hace_crypto_algs(hace_dev); 90 #endif 91 } 92 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, }, 96 {}, 97 }; 98 99 static int aspeed_hace_probe(struct platform_device *pdev) 100 { 101 struct aspeed_engine_crypto *crypto_engine; 102 struct aspeed_engine_hash *hash_engine; 103 struct aspeed_hace_dev *hace_dev; 104 int rc; 105 106 hace_dev = devm_kzalloc(&pdev->dev, sizeof(struct aspeed_hace_dev), 107 GFP_KERNEL); 108 if (!hace_dev) 109 return -ENOMEM; 110 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"); 114 return -EINVAL; 115 } 116 117 hace_dev->dev = &pdev->dev; 118 hash_engine = &hace_dev->hash_engine; 119 crypto_engine = &hace_dev->crypto_engine; 120 121 platform_set_drvdata(pdev, hace_dev); 122 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); 126 127 /* Get irq number and register it */ 128 hace_dev->irq = platform_get_irq(pdev, 0); 129 if (hace_dev->irq < 0) 130 return hace_dev->irq; 131 132 rc = devm_request_irq(&pdev->dev, hace_dev->irq, aspeed_hace_irq, 0, 133 dev_name(&pdev->dev), hace_dev); 134 if (rc) 135 return rc; 136 137 /* Get clk and enable it */ 138 hace_dev->clk = devm_clk_get(&pdev->dev, NULL); 139 if (IS_ERR(hace_dev->clk)) { 140 dev_err(&pdev->dev, "Failed to get clk\n"); 141 return -ENODEV; 142 } 143 144 rc = clk_prepare_enable(hace_dev->clk); 145 if (rc) { 146 dev_err(&pdev->dev, "Failed to enable clock 0x%x\n", rc); 147 return rc; 148 } 149 150 /* Initialize crypto hardware engine structure for hash */ 151 hace_dev->crypt_engine_hash = crypto_engine_alloc_init(hace_dev->dev, 152 true); 153 if (!hace_dev->crypt_engine_hash) { 154 rc = -ENOMEM; 155 goto clk_exit; 156 } 157 158 rc = crypto_engine_start(hace_dev->crypt_engine_hash); 159 if (rc) 160 goto err_engine_hash_start; 161 162 tasklet_init(&hash_engine->done_task, aspeed_hace_hash_done_task, 163 (unsigned long)hace_dev); 164 165 /* Initialize crypto hardware engine structure for crypto */ 166 hace_dev->crypt_engine_crypto = crypto_engine_alloc_init(hace_dev->dev, 167 true); 168 if (!hace_dev->crypt_engine_crypto) { 169 rc = -ENOMEM; 170 goto err_engine_hash_start; 171 } 172 173 rc = crypto_engine_start(hace_dev->crypt_engine_crypto); 174 if (rc) 175 goto err_engine_crypto_start; 176 177 tasklet_init(&crypto_engine->done_task, aspeed_hace_crypto_done_task, 178 (unsigned long)hace_dev); 179 180 /* Allocate DMA buffer for hash engine input used */ 181 hash_engine->ahash_src_addr = 182 dmam_alloc_coherent(&pdev->dev, 183 ASPEED_HASH_SRC_DMA_BUF_LEN, 184 &hash_engine->ahash_src_dma_addr, 185 GFP_KERNEL); 186 if (!hash_engine->ahash_src_addr) { 187 dev_err(&pdev->dev, "Failed to allocate dma buffer\n"); 188 rc = -ENOMEM; 189 goto err_engine_crypto_start; 190 } 191 192 /* Allocate DMA buffer for crypto engine context used */ 193 crypto_engine->cipher_ctx = 194 dmam_alloc_coherent(&pdev->dev, 195 PAGE_SIZE, 196 &crypto_engine->cipher_ctx_dma, 197 GFP_KERNEL); 198 if (!crypto_engine->cipher_ctx) { 199 dev_err(&pdev->dev, "Failed to allocate cipher ctx dma\n"); 200 rc = -ENOMEM; 201 goto err_engine_crypto_start; 202 } 203 204 /* Allocate DMA buffer for crypto engine input used */ 205 crypto_engine->cipher_addr = 206 dmam_alloc_coherent(&pdev->dev, 207 ASPEED_CRYPTO_SRC_DMA_BUF_LEN, 208 &crypto_engine->cipher_dma_addr, 209 GFP_KERNEL); 210 if (!crypto_engine->cipher_addr) { 211 dev_err(&pdev->dev, "Failed to allocate cipher addr dma\n"); 212 rc = -ENOMEM; 213 goto err_engine_crypto_start; 214 } 215 216 /* Allocate DMA buffer for crypto engine output used */ 217 if (hace_dev->version == AST2600_VERSION) { 218 crypto_engine->dst_sg_addr = 219 dmam_alloc_coherent(&pdev->dev, 220 ASPEED_CRYPTO_DST_DMA_BUF_LEN, 221 &crypto_engine->dst_sg_dma_addr, 222 GFP_KERNEL); 223 if (!crypto_engine->dst_sg_addr) { 224 dev_err(&pdev->dev, "Failed to allocate dst_sg dma\n"); 225 rc = -ENOMEM; 226 goto err_engine_crypto_start; 227 } 228 } 229 230 aspeed_hace_register(hace_dev); 231 232 dev_info(&pdev->dev, "Aspeed Crypto Accelerator successfully registered\n"); 233 234 return 0; 235 236 err_engine_crypto_start: 237 crypto_engine_exit(hace_dev->crypt_engine_crypto); 238 err_engine_hash_start: 239 crypto_engine_exit(hace_dev->crypt_engine_hash); 240 clk_exit: 241 clk_disable_unprepare(hace_dev->clk); 242 243 return rc; 244 } 245 246 static void aspeed_hace_remove(struct platform_device *pdev) 247 { 248 struct aspeed_hace_dev *hace_dev = platform_get_drvdata(pdev); 249 struct aspeed_engine_crypto *crypto_engine = &hace_dev->crypto_engine; 250 struct aspeed_engine_hash *hash_engine = &hace_dev->hash_engine; 251 252 aspeed_hace_unregister(hace_dev); 253 254 crypto_engine_exit(hace_dev->crypt_engine_hash); 255 crypto_engine_exit(hace_dev->crypt_engine_crypto); 256 257 tasklet_kill(&hash_engine->done_task); 258 tasklet_kill(&crypto_engine->done_task); 259 260 clk_disable_unprepare(hace_dev->clk); 261 } 262 263 MODULE_DEVICE_TABLE(of, aspeed_hace_of_matches); 264 265 static struct platform_driver aspeed_hace_driver = { 266 .probe = aspeed_hace_probe, 267 .remove = aspeed_hace_remove, 268 .driver = { 269 .name = KBUILD_MODNAME, 270 .of_match_table = aspeed_hace_of_matches, 271 }, 272 }; 273 274 module_platform_driver(aspeed_hace_driver); 275 276 MODULE_AUTHOR("Neal Liu <neal_liu@aspeedtech.com>"); 277 MODULE_DESCRIPTION("Aspeed HACE driver Crypto Accelerator"); 278 MODULE_LICENSE("GPL"); 279