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 <linux/clk.h> 11 #include <linux/delay.h> 12 #include <linux/interrupt.h> 13 #include <linux/iopoll.h> 14 #include <linux/module.h> 15 #include <linux/of_device.h> 16 #include <linux/platform_device.h> 17 #include <linux/pm_runtime.h> 18 #include <linux/reset.h> 19 20 #include "jh7110-cryp.h" 21 22 #define DRIVER_NAME "jh7110-crypto" 23 24 struct starfive_dev_list { 25 struct list_head dev_list; 26 spinlock_t lock; /* protect dev_list */ 27 }; 28 29 static struct starfive_dev_list dev_list = { 30 .dev_list = LIST_HEAD_INIT(dev_list.dev_list), 31 .lock = __SPIN_LOCK_UNLOCKED(dev_list.lock), 32 }; 33 34 struct starfive_cryp_dev *starfive_cryp_find_dev(struct starfive_cryp_ctx *ctx) 35 { 36 struct starfive_cryp_dev *cryp = NULL, *tmp; 37 38 spin_lock_bh(&dev_list.lock); 39 if (!ctx->cryp) { 40 list_for_each_entry(tmp, &dev_list.dev_list, list) { 41 cryp = tmp; 42 break; 43 } 44 ctx->cryp = cryp; 45 } else { 46 cryp = ctx->cryp; 47 } 48 49 spin_unlock_bh(&dev_list.lock); 50 51 return cryp; 52 } 53 54 static int starfive_dma_init(struct starfive_cryp_dev *cryp) 55 { 56 dma_cap_mask_t mask; 57 58 dma_cap_zero(mask); 59 dma_cap_set(DMA_SLAVE, mask); 60 61 cryp->tx = dma_request_chan(cryp->dev, "tx"); 62 if (IS_ERR(cryp->tx)) 63 return dev_err_probe(cryp->dev, PTR_ERR(cryp->tx), 64 "Error requesting tx dma channel.\n"); 65 66 cryp->rx = dma_request_chan(cryp->dev, "rx"); 67 if (IS_ERR(cryp->rx)) { 68 dma_release_channel(cryp->tx); 69 return dev_err_probe(cryp->dev, PTR_ERR(cryp->rx), 70 "Error requesting rx dma channel.\n"); 71 } 72 73 return 0; 74 } 75 76 static void starfive_dma_cleanup(struct starfive_cryp_dev *cryp) 77 { 78 dma_release_channel(cryp->tx); 79 dma_release_channel(cryp->rx); 80 } 81 82 static irqreturn_t starfive_cryp_irq(int irq, void *priv) 83 { 84 u32 status; 85 struct starfive_cryp_dev *cryp = (struct starfive_cryp_dev *)priv; 86 87 status = readl(cryp->base + STARFIVE_IE_FLAG_OFFSET); 88 if (status & STARFIVE_IE_FLAG_HASH_DONE) { 89 status = readl(cryp->base + STARFIVE_IE_MASK_OFFSET); 90 status |= STARFIVE_IE_MASK_HASH_DONE; 91 writel(status, cryp->base + STARFIVE_IE_MASK_OFFSET); 92 tasklet_schedule(&cryp->hash_done); 93 } 94 95 if (status & STARFIVE_IE_FLAG_PKA_DONE) { 96 status = readl(cryp->base + STARFIVE_IE_MASK_OFFSET); 97 status |= STARFIVE_IE_MASK_PKA_DONE; 98 writel(status, cryp->base + STARFIVE_IE_MASK_OFFSET); 99 complete(&cryp->pka_done); 100 } 101 102 return IRQ_HANDLED; 103 } 104 105 static int starfive_cryp_probe(struct platform_device *pdev) 106 { 107 struct starfive_cryp_dev *cryp; 108 struct resource *res; 109 int irq; 110 int ret; 111 112 cryp = devm_kzalloc(&pdev->dev, sizeof(*cryp), GFP_KERNEL); 113 if (!cryp) 114 return -ENOMEM; 115 116 platform_set_drvdata(pdev, cryp); 117 cryp->dev = &pdev->dev; 118 119 cryp->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 120 if (IS_ERR(cryp->base)) 121 return dev_err_probe(&pdev->dev, PTR_ERR(cryp->base), 122 "Error remapping memory for platform device\n"); 123 124 tasklet_init(&cryp->hash_done, starfive_hash_done_task, (unsigned long)cryp); 125 126 cryp->phys_base = res->start; 127 cryp->dma_maxburst = 32; 128 129 cryp->hclk = devm_clk_get(&pdev->dev, "hclk"); 130 if (IS_ERR(cryp->hclk)) 131 return dev_err_probe(&pdev->dev, PTR_ERR(cryp->hclk), 132 "Error getting hardware reference clock\n"); 133 134 cryp->ahb = devm_clk_get(&pdev->dev, "ahb"); 135 if (IS_ERR(cryp->ahb)) 136 return dev_err_probe(&pdev->dev, PTR_ERR(cryp->ahb), 137 "Error getting ahb reference clock\n"); 138 139 cryp->rst = devm_reset_control_get_shared(cryp->dev, NULL); 140 if (IS_ERR(cryp->rst)) 141 return dev_err_probe(&pdev->dev, PTR_ERR(cryp->rst), 142 "Error getting hardware reset line\n"); 143 144 init_completion(&cryp->pka_done); 145 146 irq = platform_get_irq(pdev, 0); 147 if (irq < 0) 148 return irq; 149 150 ret = devm_request_irq(&pdev->dev, irq, starfive_cryp_irq, 0, pdev->name, 151 (void *)cryp); 152 if (ret) 153 return dev_err_probe(&pdev->dev, irq, 154 "Failed to register interrupt handler\n"); 155 156 clk_prepare_enable(cryp->hclk); 157 clk_prepare_enable(cryp->ahb); 158 reset_control_deassert(cryp->rst); 159 160 spin_lock(&dev_list.lock); 161 list_add(&cryp->list, &dev_list.dev_list); 162 spin_unlock(&dev_list.lock); 163 164 ret = starfive_dma_init(cryp); 165 if (ret) { 166 if (ret == -EPROBE_DEFER) 167 goto err_probe_defer; 168 else 169 goto err_dma_init; 170 } 171 172 /* Initialize crypto engine */ 173 cryp->engine = crypto_engine_alloc_init(&pdev->dev, 1); 174 if (!cryp->engine) { 175 ret = -ENOMEM; 176 goto err_engine; 177 } 178 179 ret = crypto_engine_start(cryp->engine); 180 if (ret) 181 goto err_engine_start; 182 183 ret = starfive_hash_register_algs(); 184 if (ret) 185 goto err_algs_hash; 186 187 ret = starfive_rsa_register_algs(); 188 if (ret) 189 goto err_algs_rsa; 190 191 return 0; 192 193 err_algs_rsa: 194 starfive_hash_unregister_algs(); 195 err_algs_hash: 196 crypto_engine_stop(cryp->engine); 197 err_engine_start: 198 crypto_engine_exit(cryp->engine); 199 err_engine: 200 starfive_dma_cleanup(cryp); 201 err_dma_init: 202 spin_lock(&dev_list.lock); 203 list_del(&cryp->list); 204 spin_unlock(&dev_list.lock); 205 206 clk_disable_unprepare(cryp->hclk); 207 clk_disable_unprepare(cryp->ahb); 208 reset_control_assert(cryp->rst); 209 210 tasklet_kill(&cryp->hash_done); 211 err_probe_defer: 212 return ret; 213 } 214 215 static int starfive_cryp_remove(struct platform_device *pdev) 216 { 217 struct starfive_cryp_dev *cryp = platform_get_drvdata(pdev); 218 219 starfive_hash_unregister_algs(); 220 starfive_rsa_unregister_algs(); 221 222 tasklet_kill(&cryp->hash_done); 223 224 crypto_engine_stop(cryp->engine); 225 crypto_engine_exit(cryp->engine); 226 227 starfive_dma_cleanup(cryp); 228 229 spin_lock(&dev_list.lock); 230 list_del(&cryp->list); 231 spin_unlock(&dev_list.lock); 232 233 clk_disable_unprepare(cryp->hclk); 234 clk_disable_unprepare(cryp->ahb); 235 reset_control_assert(cryp->rst); 236 237 return 0; 238 } 239 240 static const struct of_device_id starfive_dt_ids[] __maybe_unused = { 241 { .compatible = "starfive,jh7110-crypto", .data = NULL}, 242 {}, 243 }; 244 MODULE_DEVICE_TABLE(of, starfive_dt_ids); 245 246 static struct platform_driver starfive_cryp_driver = { 247 .probe = starfive_cryp_probe, 248 .remove = starfive_cryp_remove, 249 .driver = { 250 .name = DRIVER_NAME, 251 .of_match_table = starfive_dt_ids, 252 }, 253 }; 254 255 module_platform_driver(starfive_cryp_driver); 256 257 MODULE_LICENSE("GPL"); 258 MODULE_DESCRIPTION("StarFive JH7110 Cryptographic Module"); 259