crypto: starfive - Add crypto engine support
[platform/kernel/linux-starfive.git] / drivers / crypto / starfive / jh7110-cryp.c
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             "starfive-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         cryp->tx = NULL;
59         cryp->rx = NULL;
60
61         dma_cap_zero(mask);
62         dma_cap_set(DMA_SLAVE, mask);
63
64         cryp->tx = dma_request_chan(cryp->dev, "tx");
65         if (IS_ERR(cryp->tx))
66                 return dev_err_probe(cryp->dev, PTR_ERR(cryp->tx),
67                                      "Error requesting tx dma channel.\n");
68
69         cryp->rx = dma_request_chan(cryp->dev, "rx");
70         if (IS_ERR(cryp->rx)) {
71                 dma_release_channel(cryp->tx);
72                 return dev_err_probe(cryp->dev, PTR_ERR(cryp->rx),
73                                      "Error requesting rx dma channel.\n");
74         }
75
76         init_completion(&cryp->tx_comp);
77         init_completion(&cryp->rx_comp);
78
79         return 0;
80 }
81
82 static void starfive_dma_cleanup(struct starfive_cryp_dev *cryp)
83 {
84         dma_release_channel(cryp->tx);
85         dma_release_channel(cryp->rx);
86 }
87
88 static int starfive_cryp_probe(struct platform_device *pdev)
89 {
90         struct starfive_cryp_dev *cryp;
91         struct resource *res;
92         int ret;
93
94         cryp = devm_kzalloc(&pdev->dev, sizeof(*cryp), GFP_KERNEL);
95         if (!cryp)
96                 return -ENOMEM;
97
98         platform_set_drvdata(pdev, cryp);
99         cryp->dev = &pdev->dev;
100
101         cryp->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
102         if (IS_ERR(cryp->base))
103                 return dev_err_probe(&pdev->dev, PTR_ERR(cryp->base),
104                                      "Error remapping memory for platform device\n");
105
106         cryp->phys_base = res->start;
107         cryp->dma_maxburst = 32;
108
109         cryp->hclk = devm_clk_get(&pdev->dev, "hclk");
110         if (IS_ERR(cryp->hclk))
111                 return dev_err_probe(&pdev->dev, PTR_ERR(cryp->hclk),
112                                      "Error getting hardware reference clock\n");
113
114         cryp->ahb = devm_clk_get(&pdev->dev, "ahb");
115         if (IS_ERR(cryp->ahb))
116                 return dev_err_probe(&pdev->dev, PTR_ERR(cryp->ahb),
117                                      "Error getting ahb reference clock\n");
118
119         cryp->rst = devm_reset_control_get_shared(cryp->dev, NULL);
120         if (IS_ERR(cryp->rst))
121                 return dev_err_probe(&pdev->dev, PTR_ERR(cryp->rst),
122                                      "Error getting hardware reset line\n");
123
124         clk_prepare_enable(cryp->hclk);
125         clk_prepare_enable(cryp->ahb);
126         reset_control_deassert(cryp->rst);
127
128         spin_lock(&dev_list.lock);
129         list_add(&cryp->list, &dev_list.dev_list);
130         spin_unlock(&dev_list.lock);
131
132         ret = starfive_dma_init(cryp);
133         if (ret)
134                 goto err_dma_init;
135
136         /* Initialize crypto engine */
137         cryp->engine = crypto_engine_alloc_init(&pdev->dev, 1);
138         if (!cryp->engine) {
139                 ret = -ENOMEM;
140                 goto err_engine;
141         }
142
143         ret = crypto_engine_start(cryp->engine);
144         if (ret)
145                 goto err_engine_start;
146
147         return 0;
148
149 err_engine_start:
150         crypto_engine_exit(cryp->engine);
151 err_engine:
152         starfive_dma_cleanup(cryp);
153 err_dma_init:
154         spin_lock(&dev_list.lock);
155         list_del(&cryp->list);
156         spin_unlock(&dev_list.lock);
157
158         return ret;
159 }
160
161 static int starfive_cryp_remove(struct platform_device *pdev)
162 {
163         struct starfive_cryp_dev *cryp = platform_get_drvdata(pdev);
164
165         if (!cryp)
166                 return -ENODEV;
167
168         crypto_engine_stop(cryp->engine);
169         crypto_engine_exit(cryp->engine);
170
171         starfive_dma_cleanup(cryp);
172
173         spin_lock(&dev_list.lock);
174         list_del(&cryp->list);
175         spin_unlock(&dev_list.lock);
176
177         clk_disable_unprepare(cryp->hclk);
178         clk_disable_unprepare(cryp->ahb);
179         reset_control_assert(cryp->rst);
180
181         return 0;
182 }
183
184 static const struct of_device_id starfive_dt_ids[] __maybe_unused = {
185         { .compatible = "starfive,jh7110-crypto", .data = NULL},
186         {},
187 };
188 MODULE_DEVICE_TABLE(of, starfive_dt_ids);
189
190 static struct platform_driver starfive_cryp_driver = {
191         .probe  = starfive_cryp_probe,
192         .remove = starfive_cryp_remove,
193         .driver = {
194                 .name           = DRIVER_NAME,
195                 .of_match_table = starfive_dt_ids,
196         },
197 };
198
199 module_platform_driver(starfive_cryp_driver);
200
201 MODULE_LICENSE("GPL");
202 MODULE_DESCRIPTION("StarFive Cryptographic Module");