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 21 static int rk_crypto_enable_clk(struct rk_crypto_info *dev) 22 { 23 int err; 24 25 err = clk_bulk_prepare_enable(dev->num_clks, dev->clks); 26 if (err) 27 dev_err(dev->dev, "Could not enable clock clks\n"); 28 29 return err; 30 } 31 32 static void rk_crypto_disable_clk(struct rk_crypto_info *dev) 33 { 34 clk_bulk_disable_unprepare(dev->num_clks, dev->clks); 35 } 36 37 /* 38 * Power management strategy: The device is suspended unless a TFM exists for 39 * one of the algorithms proposed by this driver. 40 */ 41 static int rk_crypto_pm_suspend(struct device *dev) 42 { 43 struct rk_crypto_info *rkdev = dev_get_drvdata(dev); 44 45 rk_crypto_disable_clk(rkdev); 46 reset_control_assert(rkdev->rst); 47 48 return 0; 49 } 50 51 static int rk_crypto_pm_resume(struct device *dev) 52 { 53 struct rk_crypto_info *rkdev = dev_get_drvdata(dev); 54 int ret; 55 56 ret = rk_crypto_enable_clk(rkdev); 57 if (ret) 58 return ret; 59 60 reset_control_deassert(rkdev->rst); 61 return 0; 62 63 } 64 65 static const struct dev_pm_ops rk_crypto_pm_ops = { 66 SET_RUNTIME_PM_OPS(rk_crypto_pm_suspend, rk_crypto_pm_resume, NULL) 67 }; 68 69 static int rk_crypto_pm_init(struct rk_crypto_info *rkdev) 70 { 71 int err; 72 73 pm_runtime_use_autosuspend(rkdev->dev); 74 pm_runtime_set_autosuspend_delay(rkdev->dev, 2000); 75 76 err = pm_runtime_set_suspended(rkdev->dev); 77 if (err) 78 return err; 79 pm_runtime_enable(rkdev->dev); 80 return err; 81 } 82 83 static void rk_crypto_pm_exit(struct rk_crypto_info *rkdev) 84 { 85 pm_runtime_disable(rkdev->dev); 86 } 87 88 static irqreturn_t rk_crypto_irq_handle(int irq, void *dev_id) 89 { 90 struct rk_crypto_info *dev = platform_get_drvdata(dev_id); 91 u32 interrupt_status; 92 93 interrupt_status = CRYPTO_READ(dev, RK_CRYPTO_INTSTS); 94 CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, interrupt_status); 95 96 dev->status = 1; 97 if (interrupt_status & 0x0a) { 98 dev_warn(dev->dev, "DMA Error\n"); 99 dev->status = 0; 100 } 101 complete(&dev->complete); 102 103 return IRQ_HANDLED; 104 } 105 106 static struct rk_crypto_tmp *rk_cipher_algs[] = { 107 &rk_ecb_aes_alg, 108 &rk_cbc_aes_alg, 109 &rk_ecb_des_alg, 110 &rk_cbc_des_alg, 111 &rk_ecb_des3_ede_alg, 112 &rk_cbc_des3_ede_alg, 113 &rk_ahash_sha1, 114 &rk_ahash_sha256, 115 &rk_ahash_md5, 116 }; 117 118 #ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG 119 static int rk_crypto_debugfs_show(struct seq_file *seq, void *v) 120 { 121 unsigned int i; 122 123 for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) { 124 if (!rk_cipher_algs[i]->dev) 125 continue; 126 switch (rk_cipher_algs[i]->type) { 127 case CRYPTO_ALG_TYPE_SKCIPHER: 128 seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n", 129 rk_cipher_algs[i]->alg.skcipher.base.cra_driver_name, 130 rk_cipher_algs[i]->alg.skcipher.base.cra_name, 131 rk_cipher_algs[i]->stat_req, rk_cipher_algs[i]->stat_fb); 132 seq_printf(seq, "\tfallback due to length: %lu\n", 133 rk_cipher_algs[i]->stat_fb_len); 134 seq_printf(seq, "\tfallback due to alignment: %lu\n", 135 rk_cipher_algs[i]->stat_fb_align); 136 seq_printf(seq, "\tfallback due to SGs: %lu\n", 137 rk_cipher_algs[i]->stat_fb_sgdiff); 138 break; 139 case CRYPTO_ALG_TYPE_AHASH: 140 seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n", 141 rk_cipher_algs[i]->alg.hash.halg.base.cra_driver_name, 142 rk_cipher_algs[i]->alg.hash.halg.base.cra_name, 143 rk_cipher_algs[i]->stat_req, rk_cipher_algs[i]->stat_fb); 144 break; 145 } 146 } 147 return 0; 148 } 149 150 DEFINE_SHOW_ATTRIBUTE(rk_crypto_debugfs); 151 #endif 152 153 static int rk_crypto_register(struct rk_crypto_info *crypto_info) 154 { 155 unsigned int i, k; 156 int err = 0; 157 158 for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) { 159 rk_cipher_algs[i]->dev = crypto_info; 160 switch (rk_cipher_algs[i]->type) { 161 case CRYPTO_ALG_TYPE_SKCIPHER: 162 dev_info(crypto_info->dev, "Register %s as %s\n", 163 rk_cipher_algs[i]->alg.skcipher.base.cra_name, 164 rk_cipher_algs[i]->alg.skcipher.base.cra_driver_name); 165 err = crypto_register_skcipher(&rk_cipher_algs[i]->alg.skcipher); 166 break; 167 case CRYPTO_ALG_TYPE_AHASH: 168 dev_info(crypto_info->dev, "Register %s as %s\n", 169 rk_cipher_algs[i]->alg.hash.halg.base.cra_name, 170 rk_cipher_algs[i]->alg.hash.halg.base.cra_driver_name); 171 err = crypto_register_ahash(&rk_cipher_algs[i]->alg.hash); 172 break; 173 default: 174 dev_err(crypto_info->dev, "unknown algorithm\n"); 175 } 176 if (err) 177 goto err_cipher_algs; 178 } 179 return 0; 180 181 err_cipher_algs: 182 for (k = 0; k < i; k++) { 183 if (rk_cipher_algs[i]->type == CRYPTO_ALG_TYPE_SKCIPHER) 184 crypto_unregister_skcipher(&rk_cipher_algs[k]->alg.skcipher); 185 else 186 crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash); 187 } 188 return err; 189 } 190 191 static void rk_crypto_unregister(void) 192 { 193 unsigned int i; 194 195 for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) { 196 if (rk_cipher_algs[i]->type == CRYPTO_ALG_TYPE_SKCIPHER) 197 crypto_unregister_skcipher(&rk_cipher_algs[i]->alg.skcipher); 198 else 199 crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash); 200 } 201 } 202 203 static const struct of_device_id crypto_of_id_table[] = { 204 { .compatible = "rockchip,rk3288-crypto" }, 205 { .compatible = "rockchip,rk3328-crypto" }, 206 {} 207 }; 208 MODULE_DEVICE_TABLE(of, crypto_of_id_table); 209 210 static int rk_crypto_probe(struct platform_device *pdev) 211 { 212 struct device *dev = &pdev->dev; 213 struct rk_crypto_info *crypto_info; 214 int err = 0; 215 216 crypto_info = devm_kzalloc(&pdev->dev, 217 sizeof(*crypto_info), GFP_KERNEL); 218 if (!crypto_info) { 219 err = -ENOMEM; 220 goto err_crypto; 221 } 222 223 crypto_info->rst = devm_reset_control_get(dev, "crypto-rst"); 224 if (IS_ERR(crypto_info->rst)) { 225 err = PTR_ERR(crypto_info->rst); 226 goto err_crypto; 227 } 228 229 reset_control_assert(crypto_info->rst); 230 usleep_range(10, 20); 231 reset_control_deassert(crypto_info->rst); 232 233 crypto_info->reg = devm_platform_ioremap_resource(pdev, 0); 234 if (IS_ERR(crypto_info->reg)) { 235 err = PTR_ERR(crypto_info->reg); 236 goto err_crypto; 237 } 238 239 crypto_info->num_clks = devm_clk_bulk_get_all(&pdev->dev, 240 &crypto_info->clks); 241 if (crypto_info->num_clks < 3) { 242 err = -EINVAL; 243 goto err_crypto; 244 } 245 246 crypto_info->irq = platform_get_irq(pdev, 0); 247 if (crypto_info->irq < 0) { 248 dev_err(&pdev->dev, "control Interrupt is not available.\n"); 249 err = crypto_info->irq; 250 goto err_crypto; 251 } 252 253 err = devm_request_irq(&pdev->dev, crypto_info->irq, 254 rk_crypto_irq_handle, IRQF_SHARED, 255 "rk-crypto", pdev); 256 257 if (err) { 258 dev_err(&pdev->dev, "irq request failed.\n"); 259 goto err_crypto; 260 } 261 262 crypto_info->dev = &pdev->dev; 263 platform_set_drvdata(pdev, crypto_info); 264 265 crypto_info->engine = crypto_engine_alloc_init(&pdev->dev, true); 266 crypto_engine_start(crypto_info->engine); 267 init_completion(&crypto_info->complete); 268 269 err = rk_crypto_pm_init(crypto_info); 270 if (err) 271 goto err_pm; 272 273 err = rk_crypto_register(crypto_info); 274 if (err) { 275 dev_err(dev, "err in register alg"); 276 goto err_register_alg; 277 } 278 279 #ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG 280 /* Ignore error of debugfs */ 281 crypto_info->dbgfs_dir = debugfs_create_dir("rk3288_crypto", NULL); 282 crypto_info->dbgfs_stats = debugfs_create_file("stats", 0444, 283 crypto_info->dbgfs_dir, 284 crypto_info, 285 &rk_crypto_debugfs_fops); 286 #endif 287 288 dev_info(dev, "Crypto Accelerator successfully registered\n"); 289 return 0; 290 291 err_register_alg: 292 rk_crypto_pm_exit(crypto_info); 293 err_pm: 294 crypto_engine_exit(crypto_info->engine); 295 err_crypto: 296 dev_err(dev, "Crypto Accelerator not successfully registered\n"); 297 return err; 298 } 299 300 static int rk_crypto_remove(struct platform_device *pdev) 301 { 302 struct rk_crypto_info *crypto_tmp = platform_get_drvdata(pdev); 303 304 #ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG 305 debugfs_remove_recursive(crypto_tmp->dbgfs_dir); 306 #endif 307 rk_crypto_unregister(); 308 rk_crypto_pm_exit(crypto_tmp); 309 crypto_engine_exit(crypto_tmp->engine); 310 return 0; 311 } 312 313 static struct platform_driver crypto_driver = { 314 .probe = rk_crypto_probe, 315 .remove = rk_crypto_remove, 316 .driver = { 317 .name = "rk3288-crypto", 318 .pm = &rk_crypto_pm_ops, 319 .of_match_table = crypto_of_id_table, 320 }, 321 }; 322 323 module_platform_driver(crypto_driver); 324 325 MODULE_AUTHOR("Zain Wang <zain.wang@rock-chips.com>"); 326 MODULE_DESCRIPTION("Support for Rockchip's cryptographic engine"); 327 MODULE_LICENSE("GPL"); 328