1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Crypto acceleration support for Rockchip RK3288
4 *
5 * Copyright (c) 2015, Fuzhou Rockchip Electronics Co., Ltd
6 *
7 * Author: Zain Wang <zain.wang@rock-chips.com>
8 *
9 * Some ideas are from marvell-cesa.c and s5p-sss.c driver.
10 */
11
12#include "rk3288_crypto.h"
13#include <linux/dma-mapping.h>
14#include <linux/module.h>
15#include <linux/platform_device.h>
16#include <linux/of.h>
17#include <linux/clk.h>
18#include <linux/crypto.h>
19#include <linux/reset.h>
20
21static int rk_crypto_enable_clk(struct rk_crypto_info *dev)
22{
23	int err;
24
25	err = clk_prepare_enable(dev->sclk);
26	if (err) {
27		dev_err(dev->dev, "[%s:%d], Couldn't enable clock sclk\n",
28			__func__, __LINE__);
29		goto err_return;
30	}
31	err = clk_prepare_enable(dev->aclk);
32	if (err) {
33		dev_err(dev->dev, "[%s:%d], Couldn't enable clock aclk\n",
34			__func__, __LINE__);
35		goto err_aclk;
36	}
37	err = clk_prepare_enable(dev->hclk);
38	if (err) {
39		dev_err(dev->dev, "[%s:%d], Couldn't enable clock hclk\n",
40			__func__, __LINE__);
41		goto err_hclk;
42	}
43	err = clk_prepare_enable(dev->dmaclk);
44	if (err) {
45		dev_err(dev->dev, "[%s:%d], Couldn't enable clock dmaclk\n",
46			__func__, __LINE__);
47		goto err_dmaclk;
48	}
49	return err;
50err_dmaclk:
51	clk_disable_unprepare(dev->hclk);
52err_hclk:
53	clk_disable_unprepare(dev->aclk);
54err_aclk:
55	clk_disable_unprepare(dev->sclk);
56err_return:
57	return err;
58}
59
60static void rk_crypto_disable_clk(struct rk_crypto_info *dev)
61{
62	clk_disable_unprepare(dev->dmaclk);
63	clk_disable_unprepare(dev->hclk);
64	clk_disable_unprepare(dev->aclk);
65	clk_disable_unprepare(dev->sclk);
66}
67
68static irqreturn_t rk_crypto_irq_handle(int irq, void *dev_id)
69{
70	struct rk_crypto_info *dev  = platform_get_drvdata(dev_id);
71	u32 interrupt_status;
72
73	interrupt_status = CRYPTO_READ(dev, RK_CRYPTO_INTSTS);
74	CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, interrupt_status);
75
76	dev->status = 1;
77	if (interrupt_status & 0x0a) {
78		dev_warn(dev->dev, "DMA Error\n");
79		dev->status = 0;
80	}
81	complete(&dev->complete);
82
83	return IRQ_HANDLED;
84}
85
86static struct rk_crypto_tmp *rk_cipher_algs[] = {
87	&rk_ecb_aes_alg,
88	&rk_cbc_aes_alg,
89	&rk_ecb_des_alg,
90	&rk_cbc_des_alg,
91	&rk_ecb_des3_ede_alg,
92	&rk_cbc_des3_ede_alg,
93	&rk_ahash_sha1,
94	&rk_ahash_sha256,
95	&rk_ahash_md5,
96};
97
98static int rk_crypto_register(struct rk_crypto_info *crypto_info)
99{
100	unsigned int i, k;
101	int err = 0;
102
103	for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) {
104		rk_cipher_algs[i]->dev = crypto_info;
105		if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER)
106			err = crypto_register_skcipher(
107					&rk_cipher_algs[i]->alg.skcipher);
108		else
109			err = crypto_register_ahash(
110					&rk_cipher_algs[i]->alg.hash);
111		if (err)
112			goto err_cipher_algs;
113	}
114	return 0;
115
116err_cipher_algs:
117	for (k = 0; k < i; k++) {
118		if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER)
119			crypto_unregister_skcipher(&rk_cipher_algs[k]->alg.skcipher);
120		else
121			crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash);
122	}
123	return err;
124}
125
126static void rk_crypto_unregister(void)
127{
128	unsigned int i;
129
130	for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) {
131		if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER)
132			crypto_unregister_skcipher(&rk_cipher_algs[i]->alg.skcipher);
133		else
134			crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash);
135	}
136}
137
138static void rk_crypto_action(void *data)
139{
140	struct rk_crypto_info *crypto_info = data;
141
142	reset_control_assert(crypto_info->rst);
143}
144
145static const struct of_device_id crypto_of_id_table[] = {
146	{ .compatible = "rockchip,rk3288-crypto" },
147	{}
148};
149MODULE_DEVICE_TABLE(of, crypto_of_id_table);
150
151static int rk_crypto_probe(struct platform_device *pdev)
152{
153	struct device *dev = &pdev->dev;
154	struct rk_crypto_info *crypto_info;
155	int err = 0;
156
157	crypto_info = devm_kzalloc(&pdev->dev,
158				   sizeof(*crypto_info), GFP_KERNEL);
159	if (!crypto_info) {
160		err = -ENOMEM;
161		goto err_crypto;
162	}
163
164	crypto_info->rst = devm_reset_control_get(dev, "crypto-rst");
165	if (IS_ERR(crypto_info->rst)) {
166		err = PTR_ERR(crypto_info->rst);
167		goto err_crypto;
168	}
169
170	reset_control_assert(crypto_info->rst);
171	usleep_range(10, 20);
172	reset_control_deassert(crypto_info->rst);
173
174	err = devm_add_action_or_reset(dev, rk_crypto_action, crypto_info);
175	if (err)
176		goto err_crypto;
177
178	crypto_info->reg = devm_platform_ioremap_resource(pdev, 0);
179	if (IS_ERR(crypto_info->reg)) {
180		err = PTR_ERR(crypto_info->reg);
181		goto err_crypto;
182	}
183
184	crypto_info->aclk = devm_clk_get(&pdev->dev, "aclk");
185	if (IS_ERR(crypto_info->aclk)) {
186		err = PTR_ERR(crypto_info->aclk);
187		goto err_crypto;
188	}
189
190	crypto_info->hclk = devm_clk_get(&pdev->dev, "hclk");
191	if (IS_ERR(crypto_info->hclk)) {
192		err = PTR_ERR(crypto_info->hclk);
193		goto err_crypto;
194	}
195
196	crypto_info->sclk = devm_clk_get(&pdev->dev, "sclk");
197	if (IS_ERR(crypto_info->sclk)) {
198		err = PTR_ERR(crypto_info->sclk);
199		goto err_crypto;
200	}
201
202	crypto_info->dmaclk = devm_clk_get(&pdev->dev, "apb_pclk");
203	if (IS_ERR(crypto_info->dmaclk)) {
204		err = PTR_ERR(crypto_info->dmaclk);
205		goto err_crypto;
206	}
207
208	crypto_info->irq = platform_get_irq(pdev, 0);
209	if (crypto_info->irq < 0) {
210		dev_warn(crypto_info->dev,
211			 "control Interrupt is not available.\n");
212		err = crypto_info->irq;
213		goto err_crypto;
214	}
215
216	err = devm_request_irq(&pdev->dev, crypto_info->irq,
217			       rk_crypto_irq_handle, IRQF_SHARED,
218			       "rk-crypto", pdev);
219
220	if (err) {
221		dev_err(crypto_info->dev, "irq request failed.\n");
222		goto err_crypto;
223	}
224
225	crypto_info->dev = &pdev->dev;
226	platform_set_drvdata(pdev, crypto_info);
227
228	crypto_info->engine = crypto_engine_alloc_init(&pdev->dev, true);
229	crypto_engine_start(crypto_info->engine);
230	init_completion(&crypto_info->complete);
231
232	rk_crypto_enable_clk(crypto_info);
233
234	err = rk_crypto_register(crypto_info);
235	if (err) {
236		dev_err(dev, "err in register alg");
237		goto err_register_alg;
238	}
239
240	dev_info(dev, "Crypto Accelerator successfully registered\n");
241	return 0;
242
243err_register_alg:
244	crypto_engine_exit(crypto_info->engine);
245err_crypto:
246	dev_err(dev, "Crypto Accelerator not successfully registered\n");
247	return err;
248}
249
250static int rk_crypto_remove(struct platform_device *pdev)
251{
252	struct rk_crypto_info *crypto_tmp = platform_get_drvdata(pdev);
253
254	rk_crypto_unregister();
255	rk_crypto_disable_clk(crypto_tmp);
256	crypto_engine_exit(crypto_tmp->engine);
257	return 0;
258}
259
260static struct platform_driver crypto_driver = {
261	.probe		= rk_crypto_probe,
262	.remove		= rk_crypto_remove,
263	.driver		= {
264		.name	= "rk3288-crypto",
265		.of_match_table	= crypto_of_id_table,
266	},
267};
268
269module_platform_driver(crypto_driver);
270
271MODULE_AUTHOR("Zain Wang <zain.wang@rock-chips.com>");
272MODULE_DESCRIPTION("Support for Rockchip's cryptographic engine");
273MODULE_LICENSE("GPL");
274