1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Cryptographic API. 4 * 5 * Support for StarFive hardware cryptographic engine. 6 * Copyright (c) 2022 StarFive Technology 7 * 8 */ 9 10 #include <crypto/engine.h> 11 #include "jh7110-cryp.h" 12 #include <linux/clk.h> 13 #include <linux/completion.h> 14 #include <linux/err.h> 15 #include <linux/interrupt.h> 16 #include <linux/iopoll.h> 17 #include <linux/kernel.h> 18 #include <linux/module.h> 19 #include <linux/platform_device.h> 20 #include <linux/pm_runtime.h> 21 #include <linux/reset.h> 22 #include <linux/spinlock.h> 23 24 #define DRIVER_NAME "jh7110-crypto" 25 26 struct starfive_dev_list { 27 struct list_head dev_list; 28 spinlock_t lock; /* protect dev_list */ 29 }; 30 31 static struct starfive_dev_list dev_list = { 32 .dev_list = LIST_HEAD_INIT(dev_list.dev_list), 33 .lock = __SPIN_LOCK_UNLOCKED(dev_list.lock), 34 }; 35 36 struct starfive_cryp_dev *starfive_cryp_find_dev(struct starfive_cryp_ctx *ctx) 37 { 38 struct starfive_cryp_dev *cryp; 39 40 spin_lock_bh(&dev_list.lock); 41 if (!ctx->cryp) 42 ctx->cryp = list_first_entry_or_null(&dev_list.dev_list, 43 struct starfive_cryp_dev, 44 list); 45 cryp = ctx->cryp; 46 spin_unlock_bh(&dev_list.lock); 47 48 return cryp; 49 } 50 51 static u16 side_chan; 52 module_param(side_chan, ushort, 0); 53 MODULE_PARM_DESC(side_chan, "Enable side channel mitigation for AES module.\n" 54 "Enabling this feature will reduce speed performance.\n" 55 " 0 - Disabled\n" 56 " other - Enabled"); 57 58 static int starfive_dma_init(struct starfive_cryp_dev *cryp) 59 { 60 dma_cap_mask_t mask; 61 62 dma_cap_zero(mask); 63 dma_cap_set(DMA_SLAVE, mask); 64 65 cryp->tx = dma_request_chan(cryp->dev, "tx"); 66 if (IS_ERR(cryp->tx)) 67 return dev_err_probe(cryp->dev, PTR_ERR(cryp->tx), 68 "Error requesting tx dma channel.\n"); 69 70 cryp->rx = dma_request_chan(cryp->dev, "rx"); 71 if (IS_ERR(cryp->rx)) { 72 dma_release_channel(cryp->tx); 73 return dev_err_probe(cryp->dev, PTR_ERR(cryp->rx), 74 "Error requesting rx dma channel.\n"); 75 } 76 77 return 0; 78 } 79 80 static void starfive_dma_cleanup(struct starfive_cryp_dev *cryp) 81 { 82 dma_release_channel(cryp->tx); 83 dma_release_channel(cryp->rx); 84 } 85 86 static int starfive_cryp_probe(struct platform_device *pdev) 87 { 88 struct starfive_cryp_dev *cryp; 89 struct resource *res; 90 int ret; 91 92 cryp = devm_kzalloc(&pdev->dev, sizeof(*cryp), GFP_KERNEL); 93 if (!cryp) 94 return -ENOMEM; 95 96 platform_set_drvdata(pdev, cryp); 97 cryp->dev = &pdev->dev; 98 99 cryp->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 100 if (IS_ERR(cryp->base)) 101 return dev_err_probe(&pdev->dev, PTR_ERR(cryp->base), 102 "Error remapping memory for platform device\n"); 103 104 cryp->phys_base = res->start; 105 cryp->dma_maxburst = 32; 106 cryp->side_chan = side_chan; 107 108 cryp->hclk = devm_clk_get(&pdev->dev, "hclk"); 109 if (IS_ERR(cryp->hclk)) 110 return dev_err_probe(&pdev->dev, PTR_ERR(cryp->hclk), 111 "Error getting hardware reference clock\n"); 112 113 cryp->ahb = devm_clk_get(&pdev->dev, "ahb"); 114 if (IS_ERR(cryp->ahb)) 115 return dev_err_probe(&pdev->dev, PTR_ERR(cryp->ahb), 116 "Error getting ahb reference clock\n"); 117 118 cryp->rst = devm_reset_control_get_shared(cryp->dev, NULL); 119 if (IS_ERR(cryp->rst)) 120 return dev_err_probe(&pdev->dev, PTR_ERR(cryp->rst), 121 "Error getting hardware reset line\n"); 122 123 clk_prepare_enable(cryp->hclk); 124 clk_prepare_enable(cryp->ahb); 125 reset_control_deassert(cryp->rst); 126 127 spin_lock(&dev_list.lock); 128 list_add(&cryp->list, &dev_list.dev_list); 129 spin_unlock(&dev_list.lock); 130 131 ret = starfive_dma_init(cryp); 132 if (ret) 133 goto err_dma_init; 134 135 /* Initialize crypto engine */ 136 cryp->engine = crypto_engine_alloc_init(&pdev->dev, 1); 137 if (!cryp->engine) { 138 ret = -ENOMEM; 139 goto err_engine; 140 } 141 142 ret = crypto_engine_start(cryp->engine); 143 if (ret) 144 goto err_engine_start; 145 146 ret = starfive_aes_register_algs(); 147 if (ret) 148 goto err_engine_start; 149 150 ret = starfive_hash_register_algs(); 151 if (ret) 152 goto err_algs_hash; 153 154 ret = starfive_rsa_register_algs(); 155 if (ret) 156 goto err_algs_rsa; 157 158 return 0; 159 160 err_algs_rsa: 161 starfive_hash_unregister_algs(); 162 err_algs_hash: 163 starfive_aes_unregister_algs(); 164 err_engine_start: 165 crypto_engine_exit(cryp->engine); 166 err_engine: 167 starfive_dma_cleanup(cryp); 168 err_dma_init: 169 spin_lock(&dev_list.lock); 170 list_del(&cryp->list); 171 spin_unlock(&dev_list.lock); 172 173 clk_disable_unprepare(cryp->hclk); 174 clk_disable_unprepare(cryp->ahb); 175 reset_control_assert(cryp->rst); 176 177 return ret; 178 } 179 180 static void starfive_cryp_remove(struct platform_device *pdev) 181 { 182 struct starfive_cryp_dev *cryp = platform_get_drvdata(pdev); 183 184 starfive_aes_unregister_algs(); 185 starfive_hash_unregister_algs(); 186 starfive_rsa_unregister_algs(); 187 188 crypto_engine_exit(cryp->engine); 189 190 starfive_dma_cleanup(cryp); 191 192 spin_lock(&dev_list.lock); 193 list_del(&cryp->list); 194 spin_unlock(&dev_list.lock); 195 196 clk_disable_unprepare(cryp->hclk); 197 clk_disable_unprepare(cryp->ahb); 198 reset_control_assert(cryp->rst); 199 } 200 201 static const struct of_device_id starfive_dt_ids[] __maybe_unused = { 202 { .compatible = "starfive,jh7110-crypto", .data = NULL}, 203 {}, 204 }; 205 MODULE_DEVICE_TABLE(of, starfive_dt_ids); 206 207 static struct platform_driver starfive_cryp_driver = { 208 .probe = starfive_cryp_probe, 209 .remove = starfive_cryp_remove, 210 .driver = { 211 .name = DRIVER_NAME, 212 .of_match_table = starfive_dt_ids, 213 }, 214 }; 215 216 module_platform_driver(starfive_cryp_driver); 217 218 MODULE_LICENSE("GPL"); 219 MODULE_DESCRIPTION("StarFive JH7110 Cryptographic Module"); 220