18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Crypto acceleration support for Rockchip RK3288 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2015, Fuzhou Rockchip Electronics Co., Ltd 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Zain Wang <zain.wang@rock-chips.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Some ideas are from marvell-cesa.c and s5p-sss.c driver. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "rk3288_crypto.h" 138c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/of.h> 178c2ecf20Sopenharmony_ci#include <linux/clk.h> 188c2ecf20Sopenharmony_ci#include <linux/crypto.h> 198c2ecf20Sopenharmony_ci#include <linux/reset.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic int rk_crypto_enable_clk(struct rk_crypto_info *dev) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci int err; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci err = clk_prepare_enable(dev->sclk); 268c2ecf20Sopenharmony_ci if (err) { 278c2ecf20Sopenharmony_ci dev_err(dev->dev, "[%s:%d], Couldn't enable clock sclk\n", 288c2ecf20Sopenharmony_ci __func__, __LINE__); 298c2ecf20Sopenharmony_ci goto err_return; 308c2ecf20Sopenharmony_ci } 318c2ecf20Sopenharmony_ci err = clk_prepare_enable(dev->aclk); 328c2ecf20Sopenharmony_ci if (err) { 338c2ecf20Sopenharmony_ci dev_err(dev->dev, "[%s:%d], Couldn't enable clock aclk\n", 348c2ecf20Sopenharmony_ci __func__, __LINE__); 358c2ecf20Sopenharmony_ci goto err_aclk; 368c2ecf20Sopenharmony_ci } 378c2ecf20Sopenharmony_ci err = clk_prepare_enable(dev->hclk); 388c2ecf20Sopenharmony_ci if (err) { 398c2ecf20Sopenharmony_ci dev_err(dev->dev, "[%s:%d], Couldn't enable clock hclk\n", 408c2ecf20Sopenharmony_ci __func__, __LINE__); 418c2ecf20Sopenharmony_ci goto err_hclk; 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci err = clk_prepare_enable(dev->dmaclk); 448c2ecf20Sopenharmony_ci if (err) { 458c2ecf20Sopenharmony_ci dev_err(dev->dev, "[%s:%d], Couldn't enable clock dmaclk\n", 468c2ecf20Sopenharmony_ci __func__, __LINE__); 478c2ecf20Sopenharmony_ci goto err_dmaclk; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci return err; 508c2ecf20Sopenharmony_cierr_dmaclk: 518c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->hclk); 528c2ecf20Sopenharmony_cierr_hclk: 538c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->aclk); 548c2ecf20Sopenharmony_cierr_aclk: 558c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->sclk); 568c2ecf20Sopenharmony_cierr_return: 578c2ecf20Sopenharmony_ci return err; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic void rk_crypto_disable_clk(struct rk_crypto_info *dev) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->dmaclk); 638c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->hclk); 648c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->aclk); 658c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->sclk); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic irqreturn_t rk_crypto_irq_handle(int irq, void *dev_id) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct rk_crypto_info *dev = platform_get_drvdata(dev_id); 718c2ecf20Sopenharmony_ci u32 interrupt_status; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci interrupt_status = CRYPTO_READ(dev, RK_CRYPTO_INTSTS); 748c2ecf20Sopenharmony_ci CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, interrupt_status); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci dev->status = 1; 778c2ecf20Sopenharmony_ci if (interrupt_status & 0x0a) { 788c2ecf20Sopenharmony_ci dev_warn(dev->dev, "DMA Error\n"); 798c2ecf20Sopenharmony_ci dev->status = 0; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci complete(&dev->complete); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci return IRQ_HANDLED; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic struct rk_crypto_tmp *rk_cipher_algs[] = { 878c2ecf20Sopenharmony_ci &rk_ecb_aes_alg, 888c2ecf20Sopenharmony_ci &rk_cbc_aes_alg, 898c2ecf20Sopenharmony_ci &rk_ecb_des_alg, 908c2ecf20Sopenharmony_ci &rk_cbc_des_alg, 918c2ecf20Sopenharmony_ci &rk_ecb_des3_ede_alg, 928c2ecf20Sopenharmony_ci &rk_cbc_des3_ede_alg, 938c2ecf20Sopenharmony_ci &rk_ahash_sha1, 948c2ecf20Sopenharmony_ci &rk_ahash_sha256, 958c2ecf20Sopenharmony_ci &rk_ahash_md5, 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic int rk_crypto_register(struct rk_crypto_info *crypto_info) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci unsigned int i, k; 1018c2ecf20Sopenharmony_ci int err = 0; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) { 1048c2ecf20Sopenharmony_ci rk_cipher_algs[i]->dev = crypto_info; 1058c2ecf20Sopenharmony_ci if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER) 1068c2ecf20Sopenharmony_ci err = crypto_register_skcipher( 1078c2ecf20Sopenharmony_ci &rk_cipher_algs[i]->alg.skcipher); 1088c2ecf20Sopenharmony_ci else 1098c2ecf20Sopenharmony_ci err = crypto_register_ahash( 1108c2ecf20Sopenharmony_ci &rk_cipher_algs[i]->alg.hash); 1118c2ecf20Sopenharmony_ci if (err) 1128c2ecf20Sopenharmony_ci goto err_cipher_algs; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cierr_cipher_algs: 1178c2ecf20Sopenharmony_ci for (k = 0; k < i; k++) { 1188c2ecf20Sopenharmony_ci if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER) 1198c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&rk_cipher_algs[k]->alg.skcipher); 1208c2ecf20Sopenharmony_ci else 1218c2ecf20Sopenharmony_ci crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash); 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci return err; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic void rk_crypto_unregister(void) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci unsigned int i; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) { 1318c2ecf20Sopenharmony_ci if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER) 1328c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&rk_cipher_algs[i]->alg.skcipher); 1338c2ecf20Sopenharmony_ci else 1348c2ecf20Sopenharmony_ci crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash); 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic void rk_crypto_action(void *data) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct rk_crypto_info *crypto_info = data; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci reset_control_assert(crypto_info->rst); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic const struct of_device_id crypto_of_id_table[] = { 1468c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3288-crypto" }, 1478c2ecf20Sopenharmony_ci {} 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, crypto_of_id_table); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic int rk_crypto_probe(struct platform_device *pdev) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 1548c2ecf20Sopenharmony_ci struct rk_crypto_info *crypto_info; 1558c2ecf20Sopenharmony_ci int err = 0; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci crypto_info = devm_kzalloc(&pdev->dev, 1588c2ecf20Sopenharmony_ci sizeof(*crypto_info), GFP_KERNEL); 1598c2ecf20Sopenharmony_ci if (!crypto_info) { 1608c2ecf20Sopenharmony_ci err = -ENOMEM; 1618c2ecf20Sopenharmony_ci goto err_crypto; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci crypto_info->rst = devm_reset_control_get(dev, "crypto-rst"); 1658c2ecf20Sopenharmony_ci if (IS_ERR(crypto_info->rst)) { 1668c2ecf20Sopenharmony_ci err = PTR_ERR(crypto_info->rst); 1678c2ecf20Sopenharmony_ci goto err_crypto; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci reset_control_assert(crypto_info->rst); 1718c2ecf20Sopenharmony_ci usleep_range(10, 20); 1728c2ecf20Sopenharmony_ci reset_control_deassert(crypto_info->rst); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci err = devm_add_action_or_reset(dev, rk_crypto_action, crypto_info); 1758c2ecf20Sopenharmony_ci if (err) 1768c2ecf20Sopenharmony_ci goto err_crypto; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci crypto_info->reg = devm_platform_ioremap_resource(pdev, 0); 1798c2ecf20Sopenharmony_ci if (IS_ERR(crypto_info->reg)) { 1808c2ecf20Sopenharmony_ci err = PTR_ERR(crypto_info->reg); 1818c2ecf20Sopenharmony_ci goto err_crypto; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci crypto_info->aclk = devm_clk_get(&pdev->dev, "aclk"); 1858c2ecf20Sopenharmony_ci if (IS_ERR(crypto_info->aclk)) { 1868c2ecf20Sopenharmony_ci err = PTR_ERR(crypto_info->aclk); 1878c2ecf20Sopenharmony_ci goto err_crypto; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci crypto_info->hclk = devm_clk_get(&pdev->dev, "hclk"); 1918c2ecf20Sopenharmony_ci if (IS_ERR(crypto_info->hclk)) { 1928c2ecf20Sopenharmony_ci err = PTR_ERR(crypto_info->hclk); 1938c2ecf20Sopenharmony_ci goto err_crypto; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci crypto_info->sclk = devm_clk_get(&pdev->dev, "sclk"); 1978c2ecf20Sopenharmony_ci if (IS_ERR(crypto_info->sclk)) { 1988c2ecf20Sopenharmony_ci err = PTR_ERR(crypto_info->sclk); 1998c2ecf20Sopenharmony_ci goto err_crypto; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci crypto_info->dmaclk = devm_clk_get(&pdev->dev, "apb_pclk"); 2038c2ecf20Sopenharmony_ci if (IS_ERR(crypto_info->dmaclk)) { 2048c2ecf20Sopenharmony_ci err = PTR_ERR(crypto_info->dmaclk); 2058c2ecf20Sopenharmony_ci goto err_crypto; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci crypto_info->irq = platform_get_irq(pdev, 0); 2098c2ecf20Sopenharmony_ci if (crypto_info->irq < 0) { 2108c2ecf20Sopenharmony_ci dev_warn(crypto_info->dev, 2118c2ecf20Sopenharmony_ci "control Interrupt is not available.\n"); 2128c2ecf20Sopenharmony_ci err = crypto_info->irq; 2138c2ecf20Sopenharmony_ci goto err_crypto; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci err = devm_request_irq(&pdev->dev, crypto_info->irq, 2178c2ecf20Sopenharmony_ci rk_crypto_irq_handle, IRQF_SHARED, 2188c2ecf20Sopenharmony_ci "rk-crypto", pdev); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (err) { 2218c2ecf20Sopenharmony_ci dev_err(crypto_info->dev, "irq request failed.\n"); 2228c2ecf20Sopenharmony_ci goto err_crypto; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci crypto_info->dev = &pdev->dev; 2268c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, crypto_info); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci crypto_info->engine = crypto_engine_alloc_init(&pdev->dev, true); 2298c2ecf20Sopenharmony_ci crypto_engine_start(crypto_info->engine); 2308c2ecf20Sopenharmony_ci init_completion(&crypto_info->complete); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci rk_crypto_enable_clk(crypto_info); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci err = rk_crypto_register(crypto_info); 2358c2ecf20Sopenharmony_ci if (err) { 2368c2ecf20Sopenharmony_ci dev_err(dev, "err in register alg"); 2378c2ecf20Sopenharmony_ci goto err_register_alg; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci dev_info(dev, "Crypto Accelerator successfully registered\n"); 2418c2ecf20Sopenharmony_ci return 0; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cierr_register_alg: 2448c2ecf20Sopenharmony_ci crypto_engine_exit(crypto_info->engine); 2458c2ecf20Sopenharmony_cierr_crypto: 2468c2ecf20Sopenharmony_ci dev_err(dev, "Crypto Accelerator not successfully registered\n"); 2478c2ecf20Sopenharmony_ci return err; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int rk_crypto_remove(struct platform_device *pdev) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct rk_crypto_info *crypto_tmp = platform_get_drvdata(pdev); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci rk_crypto_unregister(); 2558c2ecf20Sopenharmony_ci rk_crypto_disable_clk(crypto_tmp); 2568c2ecf20Sopenharmony_ci crypto_engine_exit(crypto_tmp->engine); 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic struct platform_driver crypto_driver = { 2618c2ecf20Sopenharmony_ci .probe = rk_crypto_probe, 2628c2ecf20Sopenharmony_ci .remove = rk_crypto_remove, 2638c2ecf20Sopenharmony_ci .driver = { 2648c2ecf20Sopenharmony_ci .name = "rk3288-crypto", 2658c2ecf20Sopenharmony_ci .of_match_table = crypto_of_id_table, 2668c2ecf20Sopenharmony_ci }, 2678c2ecf20Sopenharmony_ci}; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cimodule_platform_driver(crypto_driver); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ciMODULE_AUTHOR("Zain Wang <zain.wang@rock-chips.com>"); 2728c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Support for Rockchip's cryptographic engine"); 2738c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 274