1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Crypto acceleration support for Rockchip RK3288 4 * 5 * Copyright (c) 2015, Fuzhou Rockchip Electronics Co., Ltd 6 * 7 * Author: Zain Wang <zain.wang@rock-chips.com> 8 * 9 * Some ideas are from marvell-cesa.c and s5p-sss.c driver. 10 */ 11 12#include "rk3288_crypto.h" 13#include <linux/dma-mapping.h> 14#include <linux/module.h> 15#include <linux/platform_device.h> 16#include <linux/of.h> 17#include <linux/clk.h> 18#include <linux/crypto.h> 19#include <linux/reset.h> 20 21static int rk_crypto_enable_clk(struct rk_crypto_info *dev) 22{ 23 int err; 24 25 err = clk_prepare_enable(dev->sclk); 26 if (err) { 27 dev_err(dev->dev, "[%s:%d], Couldn't enable clock sclk\n", 28 __func__, __LINE__); 29 goto err_return; 30 } 31 err = clk_prepare_enable(dev->aclk); 32 if (err) { 33 dev_err(dev->dev, "[%s:%d], Couldn't enable clock aclk\n", 34 __func__, __LINE__); 35 goto err_aclk; 36 } 37 err = clk_prepare_enable(dev->hclk); 38 if (err) { 39 dev_err(dev->dev, "[%s:%d], Couldn't enable clock hclk\n", 40 __func__, __LINE__); 41 goto err_hclk; 42 } 43 err = clk_prepare_enable(dev->dmaclk); 44 if (err) { 45 dev_err(dev->dev, "[%s:%d], Couldn't enable clock dmaclk\n", 46 __func__, __LINE__); 47 goto err_dmaclk; 48 } 49 return err; 50err_dmaclk: 51 clk_disable_unprepare(dev->hclk); 52err_hclk: 53 clk_disable_unprepare(dev->aclk); 54err_aclk: 55 clk_disable_unprepare(dev->sclk); 56err_return: 57 return err; 58} 59 60static void rk_crypto_disable_clk(struct rk_crypto_info *dev) 61{ 62 clk_disable_unprepare(dev->dmaclk); 63 clk_disable_unprepare(dev->hclk); 64 clk_disable_unprepare(dev->aclk); 65 clk_disable_unprepare(dev->sclk); 66} 67 68static irqreturn_t rk_crypto_irq_handle(int irq, void *dev_id) 69{ 70 struct rk_crypto_info *dev = platform_get_drvdata(dev_id); 71 u32 interrupt_status; 72 73 interrupt_status = CRYPTO_READ(dev, RK_CRYPTO_INTSTS); 74 CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, interrupt_status); 75 76 dev->status = 1; 77 if (interrupt_status & 0x0a) { 78 dev_warn(dev->dev, "DMA Error\n"); 79 dev->status = 0; 80 } 81 complete(&dev->complete); 82 83 return IRQ_HANDLED; 84} 85 86static struct rk_crypto_tmp *rk_cipher_algs[] = { 87 &rk_ecb_aes_alg, 88 &rk_cbc_aes_alg, 89 &rk_ecb_des_alg, 90 &rk_cbc_des_alg, 91 &rk_ecb_des3_ede_alg, 92 &rk_cbc_des3_ede_alg, 93 &rk_ahash_sha1, 94 &rk_ahash_sha256, 95 &rk_ahash_md5, 96}; 97 98static int rk_crypto_register(struct rk_crypto_info *crypto_info) 99{ 100 unsigned int i, k; 101 int err = 0; 102 103 for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) { 104 rk_cipher_algs[i]->dev = crypto_info; 105 if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER) 106 err = crypto_register_skcipher( 107 &rk_cipher_algs[i]->alg.skcipher); 108 else 109 err = crypto_register_ahash( 110 &rk_cipher_algs[i]->alg.hash); 111 if (err) 112 goto err_cipher_algs; 113 } 114 return 0; 115 116err_cipher_algs: 117 for (k = 0; k < i; k++) { 118 if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER) 119 crypto_unregister_skcipher(&rk_cipher_algs[k]->alg.skcipher); 120 else 121 crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash); 122 } 123 return err; 124} 125 126static void rk_crypto_unregister(void) 127{ 128 unsigned int i; 129 130 for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) { 131 if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER) 132 crypto_unregister_skcipher(&rk_cipher_algs[i]->alg.skcipher); 133 else 134 crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash); 135 } 136} 137 138static void rk_crypto_action(void *data) 139{ 140 struct rk_crypto_info *crypto_info = data; 141 142 reset_control_assert(crypto_info->rst); 143} 144 145static const struct of_device_id crypto_of_id_table[] = { 146 { .compatible = "rockchip,rk3288-crypto" }, 147 {} 148}; 149MODULE_DEVICE_TABLE(of, crypto_of_id_table); 150 151static int rk_crypto_probe(struct platform_device *pdev) 152{ 153 struct device *dev = &pdev->dev; 154 struct rk_crypto_info *crypto_info; 155 int err = 0; 156 157 crypto_info = devm_kzalloc(&pdev->dev, 158 sizeof(*crypto_info), GFP_KERNEL); 159 if (!crypto_info) { 160 err = -ENOMEM; 161 goto err_crypto; 162 } 163 164 crypto_info->rst = devm_reset_control_get(dev, "crypto-rst"); 165 if (IS_ERR(crypto_info->rst)) { 166 err = PTR_ERR(crypto_info->rst); 167 goto err_crypto; 168 } 169 170 reset_control_assert(crypto_info->rst); 171 usleep_range(10, 20); 172 reset_control_deassert(crypto_info->rst); 173 174 err = devm_add_action_or_reset(dev, rk_crypto_action, crypto_info); 175 if (err) 176 goto err_crypto; 177 178 crypto_info->reg = devm_platform_ioremap_resource(pdev, 0); 179 if (IS_ERR(crypto_info->reg)) { 180 err = PTR_ERR(crypto_info->reg); 181 goto err_crypto; 182 } 183 184 crypto_info->aclk = devm_clk_get(&pdev->dev, "aclk"); 185 if (IS_ERR(crypto_info->aclk)) { 186 err = PTR_ERR(crypto_info->aclk); 187 goto err_crypto; 188 } 189 190 crypto_info->hclk = devm_clk_get(&pdev->dev, "hclk"); 191 if (IS_ERR(crypto_info->hclk)) { 192 err = PTR_ERR(crypto_info->hclk); 193 goto err_crypto; 194 } 195 196 crypto_info->sclk = devm_clk_get(&pdev->dev, "sclk"); 197 if (IS_ERR(crypto_info->sclk)) { 198 err = PTR_ERR(crypto_info->sclk); 199 goto err_crypto; 200 } 201 202 crypto_info->dmaclk = devm_clk_get(&pdev->dev, "apb_pclk"); 203 if (IS_ERR(crypto_info->dmaclk)) { 204 err = PTR_ERR(crypto_info->dmaclk); 205 goto err_crypto; 206 } 207 208 crypto_info->irq = platform_get_irq(pdev, 0); 209 if (crypto_info->irq < 0) { 210 dev_warn(crypto_info->dev, 211 "control Interrupt is not available.\n"); 212 err = crypto_info->irq; 213 goto err_crypto; 214 } 215 216 err = devm_request_irq(&pdev->dev, crypto_info->irq, 217 rk_crypto_irq_handle, IRQF_SHARED, 218 "rk-crypto", pdev); 219 220 if (err) { 221 dev_err(crypto_info->dev, "irq request failed.\n"); 222 goto err_crypto; 223 } 224 225 crypto_info->dev = &pdev->dev; 226 platform_set_drvdata(pdev, crypto_info); 227 228 crypto_info->engine = crypto_engine_alloc_init(&pdev->dev, true); 229 crypto_engine_start(crypto_info->engine); 230 init_completion(&crypto_info->complete); 231 232 rk_crypto_enable_clk(crypto_info); 233 234 err = rk_crypto_register(crypto_info); 235 if (err) { 236 dev_err(dev, "err in register alg"); 237 goto err_register_alg; 238 } 239 240 dev_info(dev, "Crypto Accelerator successfully registered\n"); 241 return 0; 242 243err_register_alg: 244 crypto_engine_exit(crypto_info->engine); 245err_crypto: 246 dev_err(dev, "Crypto Accelerator not successfully registered\n"); 247 return err; 248} 249 250static int rk_crypto_remove(struct platform_device *pdev) 251{ 252 struct rk_crypto_info *crypto_tmp = platform_get_drvdata(pdev); 253 254 rk_crypto_unregister(); 255 rk_crypto_disable_clk(crypto_tmp); 256 crypto_engine_exit(crypto_tmp->engine); 257 return 0; 258} 259 260static struct platform_driver crypto_driver = { 261 .probe = rk_crypto_probe, 262 .remove = rk_crypto_remove, 263 .driver = { 264 .name = "rk3288-crypto", 265 .of_match_table = crypto_of_id_table, 266 }, 267}; 268 269module_platform_driver(crypto_driver); 270 271MODULE_AUTHOR("Zain Wang <zain.wang@rock-chips.com>"); 272MODULE_DESCRIPTION("Support for Rockchip's cryptographic engine"); 273MODULE_LICENSE("GPL"); 274