162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Crypto acceleration support for Rockchip RK3288 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2015, Fuzhou Rockchip Electronics Co., Ltd 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Zain Wang <zain.wang@rock-chips.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Some ideas are from marvell-cesa.c and s5p-sss.c driver. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "rk3288_crypto.h" 1362306a36Sopenharmony_ci#include <crypto/engine.h> 1462306a36Sopenharmony_ci#include <crypto/internal/hash.h> 1562306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 1662306a36Sopenharmony_ci#include <linux/clk.h> 1762306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1862306a36Sopenharmony_ci#include <linux/debugfs.h> 1962306a36Sopenharmony_ci#include <linux/delay.h> 2062306a36Sopenharmony_ci#include <linux/err.h> 2162306a36Sopenharmony_ci#include <linux/kernel.h> 2262306a36Sopenharmony_ci#include <linux/io.h> 2362306a36Sopenharmony_ci#include <linux/module.h> 2462306a36Sopenharmony_ci#include <linux/platform_device.h> 2562306a36Sopenharmony_ci#include <linux/of.h> 2662306a36Sopenharmony_ci#include <linux/reset.h> 2762306a36Sopenharmony_ci#include <linux/spinlock.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic struct rockchip_ip rocklist = { 3062306a36Sopenharmony_ci .dev_list = LIST_HEAD_INIT(rocklist.dev_list), 3162306a36Sopenharmony_ci .lock = __SPIN_LOCK_UNLOCKED(rocklist.lock), 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistruct rk_crypto_info *get_rk_crypto(void) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci struct rk_crypto_info *first; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci spin_lock(&rocklist.lock); 3962306a36Sopenharmony_ci first = list_first_entry_or_null(&rocklist.dev_list, 4062306a36Sopenharmony_ci struct rk_crypto_info, list); 4162306a36Sopenharmony_ci list_rotate_left(&rocklist.dev_list); 4262306a36Sopenharmony_ci spin_unlock(&rocklist.lock); 4362306a36Sopenharmony_ci return first; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic const struct rk_variant rk3288_variant = { 4762306a36Sopenharmony_ci .num_clks = 4, 4862306a36Sopenharmony_ci .rkclks = { 4962306a36Sopenharmony_ci { "sclk", 150000000}, 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic const struct rk_variant rk3328_variant = { 5462306a36Sopenharmony_ci .num_clks = 3, 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic const struct rk_variant rk3399_variant = { 5862306a36Sopenharmony_ci .num_clks = 3, 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic int rk_crypto_get_clks(struct rk_crypto_info *dev) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci int i, j, err; 6462306a36Sopenharmony_ci unsigned long cr; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci dev->num_clks = devm_clk_bulk_get_all(dev->dev, &dev->clks); 6762306a36Sopenharmony_ci if (dev->num_clks < dev->variant->num_clks) { 6862306a36Sopenharmony_ci dev_err(dev->dev, "Missing clocks, got %d instead of %d\n", 6962306a36Sopenharmony_ci dev->num_clks, dev->variant->num_clks); 7062306a36Sopenharmony_ci return -EINVAL; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci for (i = 0; i < dev->num_clks; i++) { 7462306a36Sopenharmony_ci cr = clk_get_rate(dev->clks[i].clk); 7562306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(dev->variant->rkclks); j++) { 7662306a36Sopenharmony_ci if (dev->variant->rkclks[j].max == 0) 7762306a36Sopenharmony_ci continue; 7862306a36Sopenharmony_ci if (strcmp(dev->variant->rkclks[j].name, dev->clks[i].id)) 7962306a36Sopenharmony_ci continue; 8062306a36Sopenharmony_ci if (cr > dev->variant->rkclks[j].max) { 8162306a36Sopenharmony_ci err = clk_set_rate(dev->clks[i].clk, 8262306a36Sopenharmony_ci dev->variant->rkclks[j].max); 8362306a36Sopenharmony_ci if (err) 8462306a36Sopenharmony_ci dev_err(dev->dev, "Fail downclocking %s from %lu to %lu\n", 8562306a36Sopenharmony_ci dev->variant->rkclks[j].name, cr, 8662306a36Sopenharmony_ci dev->variant->rkclks[j].max); 8762306a36Sopenharmony_ci else 8862306a36Sopenharmony_ci dev_info(dev->dev, "Downclocking %s from %lu to %lu\n", 8962306a36Sopenharmony_ci dev->variant->rkclks[j].name, cr, 9062306a36Sopenharmony_ci dev->variant->rkclks[j].max); 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int rk_crypto_enable_clk(struct rk_crypto_info *dev) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci int err; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci err = clk_bulk_prepare_enable(dev->num_clks, dev->clks); 10262306a36Sopenharmony_ci if (err) 10362306a36Sopenharmony_ci dev_err(dev->dev, "Could not enable clock clks\n"); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci return err; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic void rk_crypto_disable_clk(struct rk_crypto_info *dev) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci clk_bulk_disable_unprepare(dev->num_clks, dev->clks); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* 11462306a36Sopenharmony_ci * Power management strategy: The device is suspended until a request 11562306a36Sopenharmony_ci * is handled. For avoiding suspend/resume yoyo, the autosuspend is set to 2s. 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_cistatic int rk_crypto_pm_suspend(struct device *dev) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct rk_crypto_info *rkdev = dev_get_drvdata(dev); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci rk_crypto_disable_clk(rkdev); 12262306a36Sopenharmony_ci reset_control_assert(rkdev->rst); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return 0; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic int rk_crypto_pm_resume(struct device *dev) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct rk_crypto_info *rkdev = dev_get_drvdata(dev); 13062306a36Sopenharmony_ci int ret; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci ret = rk_crypto_enable_clk(rkdev); 13362306a36Sopenharmony_ci if (ret) 13462306a36Sopenharmony_ci return ret; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci reset_control_deassert(rkdev->rst); 13762306a36Sopenharmony_ci return 0; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic const struct dev_pm_ops rk_crypto_pm_ops = { 14262306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(rk_crypto_pm_suspend, rk_crypto_pm_resume, NULL) 14362306a36Sopenharmony_ci}; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic int rk_crypto_pm_init(struct rk_crypto_info *rkdev) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci int err; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci pm_runtime_use_autosuspend(rkdev->dev); 15062306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(rkdev->dev, 2000); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci err = pm_runtime_set_suspended(rkdev->dev); 15362306a36Sopenharmony_ci if (err) 15462306a36Sopenharmony_ci return err; 15562306a36Sopenharmony_ci pm_runtime_enable(rkdev->dev); 15662306a36Sopenharmony_ci return err; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic void rk_crypto_pm_exit(struct rk_crypto_info *rkdev) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci pm_runtime_disable(rkdev->dev); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic irqreturn_t rk_crypto_irq_handle(int irq, void *dev_id) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct rk_crypto_info *dev = platform_get_drvdata(dev_id); 16762306a36Sopenharmony_ci u32 interrupt_status; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci interrupt_status = CRYPTO_READ(dev, RK_CRYPTO_INTSTS); 17062306a36Sopenharmony_ci CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, interrupt_status); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci dev->status = 1; 17362306a36Sopenharmony_ci if (interrupt_status & 0x0a) { 17462306a36Sopenharmony_ci dev_warn(dev->dev, "DMA Error\n"); 17562306a36Sopenharmony_ci dev->status = 0; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci complete(&dev->complete); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return IRQ_HANDLED; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic struct rk_crypto_tmp *rk_cipher_algs[] = { 18362306a36Sopenharmony_ci &rk_ecb_aes_alg, 18462306a36Sopenharmony_ci &rk_cbc_aes_alg, 18562306a36Sopenharmony_ci &rk_ecb_des_alg, 18662306a36Sopenharmony_ci &rk_cbc_des_alg, 18762306a36Sopenharmony_ci &rk_ecb_des3_ede_alg, 18862306a36Sopenharmony_ci &rk_cbc_des3_ede_alg, 18962306a36Sopenharmony_ci &rk_ahash_sha1, 19062306a36Sopenharmony_ci &rk_ahash_sha256, 19162306a36Sopenharmony_ci &rk_ahash_md5, 19262306a36Sopenharmony_ci}; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int rk_crypto_debugfs_show(struct seq_file *seq, void *v) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct rk_crypto_info *dd; 19762306a36Sopenharmony_ci unsigned int i; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci spin_lock(&rocklist.lock); 20062306a36Sopenharmony_ci list_for_each_entry(dd, &rocklist.dev_list, list) { 20162306a36Sopenharmony_ci seq_printf(seq, "%s %s requests: %lu\n", 20262306a36Sopenharmony_ci dev_driver_string(dd->dev), dev_name(dd->dev), 20362306a36Sopenharmony_ci dd->nreq); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci spin_unlock(&rocklist.lock); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) { 20862306a36Sopenharmony_ci if (!rk_cipher_algs[i]->dev) 20962306a36Sopenharmony_ci continue; 21062306a36Sopenharmony_ci switch (rk_cipher_algs[i]->type) { 21162306a36Sopenharmony_ci case CRYPTO_ALG_TYPE_SKCIPHER: 21262306a36Sopenharmony_ci seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n", 21362306a36Sopenharmony_ci rk_cipher_algs[i]->alg.skcipher.base.base.cra_driver_name, 21462306a36Sopenharmony_ci rk_cipher_algs[i]->alg.skcipher.base.base.cra_name, 21562306a36Sopenharmony_ci rk_cipher_algs[i]->stat_req, rk_cipher_algs[i]->stat_fb); 21662306a36Sopenharmony_ci seq_printf(seq, "\tfallback due to length: %lu\n", 21762306a36Sopenharmony_ci rk_cipher_algs[i]->stat_fb_len); 21862306a36Sopenharmony_ci seq_printf(seq, "\tfallback due to alignment: %lu\n", 21962306a36Sopenharmony_ci rk_cipher_algs[i]->stat_fb_align); 22062306a36Sopenharmony_ci seq_printf(seq, "\tfallback due to SGs: %lu\n", 22162306a36Sopenharmony_ci rk_cipher_algs[i]->stat_fb_sgdiff); 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci case CRYPTO_ALG_TYPE_AHASH: 22462306a36Sopenharmony_ci seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n", 22562306a36Sopenharmony_ci rk_cipher_algs[i]->alg.hash.base.halg.base.cra_driver_name, 22662306a36Sopenharmony_ci rk_cipher_algs[i]->alg.hash.base.halg.base.cra_name, 22762306a36Sopenharmony_ci rk_cipher_algs[i]->stat_req, rk_cipher_algs[i]->stat_fb); 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(rk_crypto_debugfs); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic void register_debugfs(struct rk_crypto_info *crypto_info) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci struct dentry *dbgfs_dir __maybe_unused; 23962306a36Sopenharmony_ci struct dentry *dbgfs_stats __maybe_unused; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* Ignore error of debugfs */ 24262306a36Sopenharmony_ci dbgfs_dir = debugfs_create_dir("rk3288_crypto", NULL); 24362306a36Sopenharmony_ci dbgfs_stats = debugfs_create_file("stats", 0444, dbgfs_dir, &rocklist, 24462306a36Sopenharmony_ci &rk_crypto_debugfs_fops); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG 24762306a36Sopenharmony_ci rocklist.dbgfs_dir = dbgfs_dir; 24862306a36Sopenharmony_ci rocklist.dbgfs_stats = dbgfs_stats; 24962306a36Sopenharmony_ci#endif 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic int rk_crypto_register(struct rk_crypto_info *crypto_info) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci unsigned int i, k; 25562306a36Sopenharmony_ci int err = 0; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) { 25862306a36Sopenharmony_ci rk_cipher_algs[i]->dev = crypto_info; 25962306a36Sopenharmony_ci switch (rk_cipher_algs[i]->type) { 26062306a36Sopenharmony_ci case CRYPTO_ALG_TYPE_SKCIPHER: 26162306a36Sopenharmony_ci dev_info(crypto_info->dev, "Register %s as %s\n", 26262306a36Sopenharmony_ci rk_cipher_algs[i]->alg.skcipher.base.base.cra_name, 26362306a36Sopenharmony_ci rk_cipher_algs[i]->alg.skcipher.base.base.cra_driver_name); 26462306a36Sopenharmony_ci err = crypto_engine_register_skcipher(&rk_cipher_algs[i]->alg.skcipher); 26562306a36Sopenharmony_ci break; 26662306a36Sopenharmony_ci case CRYPTO_ALG_TYPE_AHASH: 26762306a36Sopenharmony_ci dev_info(crypto_info->dev, "Register %s as %s\n", 26862306a36Sopenharmony_ci rk_cipher_algs[i]->alg.hash.base.halg.base.cra_name, 26962306a36Sopenharmony_ci rk_cipher_algs[i]->alg.hash.base.halg.base.cra_driver_name); 27062306a36Sopenharmony_ci err = crypto_engine_register_ahash(&rk_cipher_algs[i]->alg.hash); 27162306a36Sopenharmony_ci break; 27262306a36Sopenharmony_ci default: 27362306a36Sopenharmony_ci dev_err(crypto_info->dev, "unknown algorithm\n"); 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci if (err) 27662306a36Sopenharmony_ci goto err_cipher_algs; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci return 0; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cierr_cipher_algs: 28162306a36Sopenharmony_ci for (k = 0; k < i; k++) { 28262306a36Sopenharmony_ci if (rk_cipher_algs[i]->type == CRYPTO_ALG_TYPE_SKCIPHER) 28362306a36Sopenharmony_ci crypto_engine_unregister_skcipher(&rk_cipher_algs[k]->alg.skcipher); 28462306a36Sopenharmony_ci else 28562306a36Sopenharmony_ci crypto_engine_unregister_ahash(&rk_cipher_algs[i]->alg.hash); 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci return err; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic void rk_crypto_unregister(void) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci unsigned int i; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) { 29562306a36Sopenharmony_ci if (rk_cipher_algs[i]->type == CRYPTO_ALG_TYPE_SKCIPHER) 29662306a36Sopenharmony_ci crypto_engine_unregister_skcipher(&rk_cipher_algs[i]->alg.skcipher); 29762306a36Sopenharmony_ci else 29862306a36Sopenharmony_ci crypto_engine_unregister_ahash(&rk_cipher_algs[i]->alg.hash); 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic const struct of_device_id crypto_of_id_table[] = { 30362306a36Sopenharmony_ci { .compatible = "rockchip,rk3288-crypto", 30462306a36Sopenharmony_ci .data = &rk3288_variant, 30562306a36Sopenharmony_ci }, 30662306a36Sopenharmony_ci { .compatible = "rockchip,rk3328-crypto", 30762306a36Sopenharmony_ci .data = &rk3328_variant, 30862306a36Sopenharmony_ci }, 30962306a36Sopenharmony_ci { .compatible = "rockchip,rk3399-crypto", 31062306a36Sopenharmony_ci .data = &rk3399_variant, 31162306a36Sopenharmony_ci }, 31262306a36Sopenharmony_ci {} 31362306a36Sopenharmony_ci}; 31462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, crypto_of_id_table); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic int rk_crypto_probe(struct platform_device *pdev) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci struct device *dev = &pdev->dev; 31962306a36Sopenharmony_ci struct rk_crypto_info *crypto_info, *first; 32062306a36Sopenharmony_ci int err = 0; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci crypto_info = devm_kzalloc(&pdev->dev, 32362306a36Sopenharmony_ci sizeof(*crypto_info), GFP_KERNEL); 32462306a36Sopenharmony_ci if (!crypto_info) { 32562306a36Sopenharmony_ci err = -ENOMEM; 32662306a36Sopenharmony_ci goto err_crypto; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci crypto_info->dev = &pdev->dev; 33062306a36Sopenharmony_ci platform_set_drvdata(pdev, crypto_info); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci crypto_info->variant = of_device_get_match_data(&pdev->dev); 33362306a36Sopenharmony_ci if (!crypto_info->variant) { 33462306a36Sopenharmony_ci dev_err(&pdev->dev, "Missing variant\n"); 33562306a36Sopenharmony_ci return -EINVAL; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci crypto_info->rst = devm_reset_control_array_get_exclusive(dev); 33962306a36Sopenharmony_ci if (IS_ERR(crypto_info->rst)) { 34062306a36Sopenharmony_ci err = PTR_ERR(crypto_info->rst); 34162306a36Sopenharmony_ci goto err_crypto; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci reset_control_assert(crypto_info->rst); 34562306a36Sopenharmony_ci usleep_range(10, 20); 34662306a36Sopenharmony_ci reset_control_deassert(crypto_info->rst); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci crypto_info->reg = devm_platform_ioremap_resource(pdev, 0); 34962306a36Sopenharmony_ci if (IS_ERR(crypto_info->reg)) { 35062306a36Sopenharmony_ci err = PTR_ERR(crypto_info->reg); 35162306a36Sopenharmony_ci goto err_crypto; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci err = rk_crypto_get_clks(crypto_info); 35562306a36Sopenharmony_ci if (err) 35662306a36Sopenharmony_ci goto err_crypto; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci crypto_info->irq = platform_get_irq(pdev, 0); 35962306a36Sopenharmony_ci if (crypto_info->irq < 0) { 36062306a36Sopenharmony_ci err = crypto_info->irq; 36162306a36Sopenharmony_ci goto err_crypto; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci err = devm_request_irq(&pdev->dev, crypto_info->irq, 36562306a36Sopenharmony_ci rk_crypto_irq_handle, IRQF_SHARED, 36662306a36Sopenharmony_ci "rk-crypto", pdev); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (err) { 36962306a36Sopenharmony_ci dev_err(&pdev->dev, "irq request failed.\n"); 37062306a36Sopenharmony_ci goto err_crypto; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci crypto_info->engine = crypto_engine_alloc_init(&pdev->dev, true); 37462306a36Sopenharmony_ci crypto_engine_start(crypto_info->engine); 37562306a36Sopenharmony_ci init_completion(&crypto_info->complete); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci err = rk_crypto_pm_init(crypto_info); 37862306a36Sopenharmony_ci if (err) 37962306a36Sopenharmony_ci goto err_pm; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci spin_lock(&rocklist.lock); 38262306a36Sopenharmony_ci first = list_first_entry_or_null(&rocklist.dev_list, 38362306a36Sopenharmony_ci struct rk_crypto_info, list); 38462306a36Sopenharmony_ci list_add_tail(&crypto_info->list, &rocklist.dev_list); 38562306a36Sopenharmony_ci spin_unlock(&rocklist.lock); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (!first) { 38862306a36Sopenharmony_ci err = rk_crypto_register(crypto_info); 38962306a36Sopenharmony_ci if (err) { 39062306a36Sopenharmony_ci dev_err(dev, "Fail to register crypto algorithms"); 39162306a36Sopenharmony_ci goto err_register_alg; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci register_debugfs(crypto_info); 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci return 0; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cierr_register_alg: 40062306a36Sopenharmony_ci rk_crypto_pm_exit(crypto_info); 40162306a36Sopenharmony_cierr_pm: 40262306a36Sopenharmony_ci crypto_engine_exit(crypto_info->engine); 40362306a36Sopenharmony_cierr_crypto: 40462306a36Sopenharmony_ci dev_err(dev, "Crypto Accelerator not successfully registered\n"); 40562306a36Sopenharmony_ci return err; 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic int rk_crypto_remove(struct platform_device *pdev) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct rk_crypto_info *crypto_tmp = platform_get_drvdata(pdev); 41162306a36Sopenharmony_ci struct rk_crypto_info *first; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci spin_lock_bh(&rocklist.lock); 41462306a36Sopenharmony_ci list_del(&crypto_tmp->list); 41562306a36Sopenharmony_ci first = list_first_entry_or_null(&rocklist.dev_list, 41662306a36Sopenharmony_ci struct rk_crypto_info, list); 41762306a36Sopenharmony_ci spin_unlock_bh(&rocklist.lock); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (!first) { 42062306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG 42162306a36Sopenharmony_ci debugfs_remove_recursive(rocklist.dbgfs_dir); 42262306a36Sopenharmony_ci#endif 42362306a36Sopenharmony_ci rk_crypto_unregister(); 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci rk_crypto_pm_exit(crypto_tmp); 42662306a36Sopenharmony_ci crypto_engine_exit(crypto_tmp->engine); 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic struct platform_driver crypto_driver = { 43162306a36Sopenharmony_ci .probe = rk_crypto_probe, 43262306a36Sopenharmony_ci .remove = rk_crypto_remove, 43362306a36Sopenharmony_ci .driver = { 43462306a36Sopenharmony_ci .name = "rk3288-crypto", 43562306a36Sopenharmony_ci .pm = &rk_crypto_pm_ops, 43662306a36Sopenharmony_ci .of_match_table = crypto_of_id_table, 43762306a36Sopenharmony_ci }, 43862306a36Sopenharmony_ci}; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cimodule_platform_driver(crypto_driver); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ciMODULE_AUTHOR("Zain Wang <zain.wang@rock-chips.com>"); 44362306a36Sopenharmony_ciMODULE_DESCRIPTION("Support for Rockchip's cryptographic engine"); 44462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 445