148fe583fSCorentin Labbe // SPDX-License-Identifier: GPL-2.0
248fe583fSCorentin Labbe /*
348fe583fSCorentin Labbe  * amlgoic-core.c - hardware cryptographic offloader for Amlogic GXL SoC
448fe583fSCorentin Labbe  *
548fe583fSCorentin Labbe  * Copyright (C) 2018-2019 Corentin Labbe <clabbe@baylibre.com>
648fe583fSCorentin Labbe  *
748fe583fSCorentin Labbe  * Core file which registers crypto algorithms supported by the hardware.
848fe583fSCorentin Labbe  */
948fe583fSCorentin Labbe #include <linux/clk.h>
1048fe583fSCorentin Labbe #include <linux/crypto.h>
1148fe583fSCorentin Labbe #include <linux/io.h>
1248fe583fSCorentin Labbe #include <linux/interrupt.h>
1348fe583fSCorentin Labbe #include <linux/irq.h>
1448fe583fSCorentin Labbe #include <linux/module.h>
1548fe583fSCorentin Labbe #include <linux/of.h>
1648fe583fSCorentin Labbe #include <linux/of_device.h>
1748fe583fSCorentin Labbe #include <linux/platform_device.h>
1848fe583fSCorentin Labbe #include <crypto/internal/skcipher.h>
1948fe583fSCorentin Labbe #include <linux/dma-mapping.h>
2048fe583fSCorentin Labbe 
2148fe583fSCorentin Labbe #include "amlogic-gxl.h"
2248fe583fSCorentin Labbe 
2348fe583fSCorentin Labbe static irqreturn_t meson_irq_handler(int irq, void *data)
2448fe583fSCorentin Labbe {
2548fe583fSCorentin Labbe 	struct meson_dev *mc = (struct meson_dev *)data;
2648fe583fSCorentin Labbe 	int flow;
2748fe583fSCorentin Labbe 	u32 p;
2848fe583fSCorentin Labbe 
2948fe583fSCorentin Labbe 	for (flow = 0; flow < MAXFLOW; flow++) {
3048fe583fSCorentin Labbe 		if (mc->irqs[flow] == irq) {
3148fe583fSCorentin Labbe 			p = readl(mc->base + ((0x04 + flow) << 2));
3248fe583fSCorentin Labbe 			if (p) {
3348fe583fSCorentin Labbe 				writel_relaxed(0xF, mc->base + ((0x4 + flow) << 2));
3448fe583fSCorentin Labbe 				mc->chanlist[flow].status = 1;
3548fe583fSCorentin Labbe 				complete(&mc->chanlist[flow].complete);
3648fe583fSCorentin Labbe 				return IRQ_HANDLED;
3748fe583fSCorentin Labbe 			}
3848fe583fSCorentin Labbe 			dev_err(mc->dev, "%s %d Got irq for flow %d but ctrl is empty\n", __func__, irq, flow);
3948fe583fSCorentin Labbe 		}
4048fe583fSCorentin Labbe 	}
4148fe583fSCorentin Labbe 
4248fe583fSCorentin Labbe 	dev_err(mc->dev, "%s %d from unknown irq\n", __func__, irq);
4348fe583fSCorentin Labbe 	return IRQ_HANDLED;
4448fe583fSCorentin Labbe }
4548fe583fSCorentin Labbe 
4648fe583fSCorentin Labbe static struct meson_alg_template mc_algs[] = {
4748fe583fSCorentin Labbe {
4848fe583fSCorentin Labbe 	.type = CRYPTO_ALG_TYPE_SKCIPHER,
4948fe583fSCorentin Labbe 	.blockmode = MESON_OPMODE_CBC,
5048fe583fSCorentin Labbe 	.alg.skcipher = {
5148fe583fSCorentin Labbe 		.base = {
5248fe583fSCorentin Labbe 			.cra_name = "cbc(aes)",
5348fe583fSCorentin Labbe 			.cra_driver_name = "cbc-aes-gxl",
5448fe583fSCorentin Labbe 			.cra_priority = 400,
5548fe583fSCorentin Labbe 			.cra_blocksize = AES_BLOCK_SIZE,
5648fe583fSCorentin Labbe 			.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |
5748fe583fSCorentin Labbe 				CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
5848fe583fSCorentin Labbe 			.cra_ctxsize = sizeof(struct meson_cipher_tfm_ctx),
5948fe583fSCorentin Labbe 			.cra_module = THIS_MODULE,
6048fe583fSCorentin Labbe 			.cra_alignmask = 0xf,
6148fe583fSCorentin Labbe 			.cra_init = meson_cipher_init,
6248fe583fSCorentin Labbe 			.cra_exit = meson_cipher_exit,
6348fe583fSCorentin Labbe 		},
6448fe583fSCorentin Labbe 		.min_keysize	= AES_MIN_KEY_SIZE,
6548fe583fSCorentin Labbe 		.max_keysize	= AES_MAX_KEY_SIZE,
6648fe583fSCorentin Labbe 		.ivsize		= AES_BLOCK_SIZE,
6748fe583fSCorentin Labbe 		.setkey		= meson_aes_setkey,
6848fe583fSCorentin Labbe 		.encrypt	= meson_skencrypt,
6948fe583fSCorentin Labbe 		.decrypt	= meson_skdecrypt,
7048fe583fSCorentin Labbe 	}
7148fe583fSCorentin Labbe },
7248fe583fSCorentin Labbe {
7348fe583fSCorentin Labbe 	.type = CRYPTO_ALG_TYPE_SKCIPHER,
7448fe583fSCorentin Labbe 	.blockmode = MESON_OPMODE_ECB,
7548fe583fSCorentin Labbe 	.alg.skcipher = {
7648fe583fSCorentin Labbe 		.base = {
7748fe583fSCorentin Labbe 			.cra_name = "ecb(aes)",
7848fe583fSCorentin Labbe 			.cra_driver_name = "ecb-aes-gxl",
7948fe583fSCorentin Labbe 			.cra_priority = 400,
8048fe583fSCorentin Labbe 			.cra_blocksize = AES_BLOCK_SIZE,
8148fe583fSCorentin Labbe 			.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |
8248fe583fSCorentin Labbe 				CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK,
8348fe583fSCorentin Labbe 			.cra_ctxsize = sizeof(struct meson_cipher_tfm_ctx),
8448fe583fSCorentin Labbe 			.cra_module = THIS_MODULE,
8548fe583fSCorentin Labbe 			.cra_alignmask = 0xf,
8648fe583fSCorentin Labbe 			.cra_init = meson_cipher_init,
8748fe583fSCorentin Labbe 			.cra_exit = meson_cipher_exit,
8848fe583fSCorentin Labbe 		},
8948fe583fSCorentin Labbe 		.min_keysize	= AES_MIN_KEY_SIZE,
9048fe583fSCorentin Labbe 		.max_keysize	= AES_MAX_KEY_SIZE,
9148fe583fSCorentin Labbe 		.setkey		= meson_aes_setkey,
9248fe583fSCorentin Labbe 		.encrypt	= meson_skencrypt,
9348fe583fSCorentin Labbe 		.decrypt	= meson_skdecrypt,
9448fe583fSCorentin Labbe 	}
9548fe583fSCorentin Labbe },
9648fe583fSCorentin Labbe };
9748fe583fSCorentin Labbe 
9848fe583fSCorentin Labbe #ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
9948fe583fSCorentin Labbe static int meson_dbgfs_read(struct seq_file *seq, void *v)
10048fe583fSCorentin Labbe {
10148fe583fSCorentin Labbe 	struct meson_dev *mc = seq->private;
10248fe583fSCorentin Labbe 	int i;
10348fe583fSCorentin Labbe 
10448fe583fSCorentin Labbe 	for (i = 0; i < MAXFLOW; i++)
10548fe583fSCorentin Labbe 		seq_printf(seq, "Channel %d: nreq %lu\n", i, mc->chanlist[i].stat_req);
10648fe583fSCorentin Labbe 
10748fe583fSCorentin Labbe 	for (i = 0; i < ARRAY_SIZE(mc_algs); i++) {
10848fe583fSCorentin Labbe 		switch (mc_algs[i].type) {
10948fe583fSCorentin Labbe 		case CRYPTO_ALG_TYPE_SKCIPHER:
11048fe583fSCorentin Labbe 			seq_printf(seq, "%s %s %lu %lu\n",
11148fe583fSCorentin Labbe 				   mc_algs[i].alg.skcipher.base.cra_driver_name,
11248fe583fSCorentin Labbe 				   mc_algs[i].alg.skcipher.base.cra_name,
11348fe583fSCorentin Labbe 				   mc_algs[i].stat_req, mc_algs[i].stat_fb);
11448fe583fSCorentin Labbe 			break;
11548fe583fSCorentin Labbe 		}
11648fe583fSCorentin Labbe 	}
11748fe583fSCorentin Labbe 	return 0;
11848fe583fSCorentin Labbe }
11948fe583fSCorentin Labbe 
12048fe583fSCorentin Labbe static int meson_dbgfs_open(struct inode *inode, struct file *file)
12148fe583fSCorentin Labbe {
12248fe583fSCorentin Labbe 	return single_open(file, meson_dbgfs_read, inode->i_private);
12348fe583fSCorentin Labbe }
12448fe583fSCorentin Labbe 
12548fe583fSCorentin Labbe static const struct file_operations meson_debugfs_fops = {
12648fe583fSCorentin Labbe 	.owner = THIS_MODULE,
12748fe583fSCorentin Labbe 	.open = meson_dbgfs_open,
12848fe583fSCorentin Labbe 	.read = seq_read,
12948fe583fSCorentin Labbe 	.llseek = seq_lseek,
13048fe583fSCorentin Labbe 	.release = single_release,
13148fe583fSCorentin Labbe };
13248fe583fSCorentin Labbe #endif
13348fe583fSCorentin Labbe 
13448fe583fSCorentin Labbe static void meson_free_chanlist(struct meson_dev *mc, int i)
13548fe583fSCorentin Labbe {
13648fe583fSCorentin Labbe 	while (i >= 0) {
13748fe583fSCorentin Labbe 		crypto_engine_exit(mc->chanlist[i].engine);
13848fe583fSCorentin Labbe 		if (mc->chanlist[i].tl)
13948fe583fSCorentin Labbe 			dma_free_coherent(mc->dev, sizeof(struct meson_desc) * MAXDESC,
14048fe583fSCorentin Labbe 					  mc->chanlist[i].tl,
14148fe583fSCorentin Labbe 					  mc->chanlist[i].t_phy);
14248fe583fSCorentin Labbe 		i--;
14348fe583fSCorentin Labbe 	}
14448fe583fSCorentin Labbe }
14548fe583fSCorentin Labbe 
14648fe583fSCorentin Labbe /*
14748fe583fSCorentin Labbe  * Allocate the channel list structure
14848fe583fSCorentin Labbe  */
14948fe583fSCorentin Labbe static int meson_allocate_chanlist(struct meson_dev *mc)
15048fe583fSCorentin Labbe {
15148fe583fSCorentin Labbe 	int i, err;
15248fe583fSCorentin Labbe 
15348fe583fSCorentin Labbe 	mc->chanlist = devm_kcalloc(mc->dev, MAXFLOW,
15448fe583fSCorentin Labbe 				    sizeof(struct meson_flow), GFP_KERNEL);
15548fe583fSCorentin Labbe 	if (!mc->chanlist)
15648fe583fSCorentin Labbe 		return -ENOMEM;
15748fe583fSCorentin Labbe 
15848fe583fSCorentin Labbe 	for (i = 0; i < MAXFLOW; i++) {
15948fe583fSCorentin Labbe 		init_completion(&mc->chanlist[i].complete);
16048fe583fSCorentin Labbe 
16148fe583fSCorentin Labbe 		mc->chanlist[i].engine = crypto_engine_alloc_init(mc->dev, true);
16248fe583fSCorentin Labbe 		if (!mc->chanlist[i].engine) {
16348fe583fSCorentin Labbe 			dev_err(mc->dev, "Cannot allocate engine\n");
16448fe583fSCorentin Labbe 			i--;
165a9704293SColin Ian King 			err = -ENOMEM;
16648fe583fSCorentin Labbe 			goto error_engine;
16748fe583fSCorentin Labbe 		}
16848fe583fSCorentin Labbe 		err = crypto_engine_start(mc->chanlist[i].engine);
16948fe583fSCorentin Labbe 		if (err) {
17048fe583fSCorentin Labbe 			dev_err(mc->dev, "Cannot start engine\n");
17148fe583fSCorentin Labbe 			goto error_engine;
17248fe583fSCorentin Labbe 		}
17348fe583fSCorentin Labbe 		mc->chanlist[i].tl = dma_alloc_coherent(mc->dev,
17448fe583fSCorentin Labbe 							sizeof(struct meson_desc) * MAXDESC,
17548fe583fSCorentin Labbe 							&mc->chanlist[i].t_phy,
17648fe583fSCorentin Labbe 							GFP_KERNEL);
17748fe583fSCorentin Labbe 		if (!mc->chanlist[i].tl) {
17848fe583fSCorentin Labbe 			err = -ENOMEM;
17948fe583fSCorentin Labbe 			goto error_engine;
18048fe583fSCorentin Labbe 		}
18148fe583fSCorentin Labbe 	}
18248fe583fSCorentin Labbe 	return 0;
18348fe583fSCorentin Labbe error_engine:
18448fe583fSCorentin Labbe 	meson_free_chanlist(mc, i);
18548fe583fSCorentin Labbe 	return err;
18648fe583fSCorentin Labbe }
18748fe583fSCorentin Labbe 
18848fe583fSCorentin Labbe static int meson_register_algs(struct meson_dev *mc)
18948fe583fSCorentin Labbe {
19048fe583fSCorentin Labbe 	int err, i;
19148fe583fSCorentin Labbe 
19248fe583fSCorentin Labbe 	for (i = 0; i < ARRAY_SIZE(mc_algs); i++) {
19348fe583fSCorentin Labbe 		mc_algs[i].mc = mc;
19448fe583fSCorentin Labbe 		switch (mc_algs[i].type) {
19548fe583fSCorentin Labbe 		case CRYPTO_ALG_TYPE_SKCIPHER:
19648fe583fSCorentin Labbe 			err = crypto_register_skcipher(&mc_algs[i].alg.skcipher);
19748fe583fSCorentin Labbe 			if (err) {
19848fe583fSCorentin Labbe 				dev_err(mc->dev, "Fail to register %s\n",
19948fe583fSCorentin Labbe 					mc_algs[i].alg.skcipher.base.cra_name);
20048fe583fSCorentin Labbe 				mc_algs[i].mc = NULL;
20148fe583fSCorentin Labbe 				return err;
20248fe583fSCorentin Labbe 			}
20348fe583fSCorentin Labbe 			break;
20448fe583fSCorentin Labbe 		}
20548fe583fSCorentin Labbe 	}
20648fe583fSCorentin Labbe 
20748fe583fSCorentin Labbe 	return 0;
20848fe583fSCorentin Labbe }
20948fe583fSCorentin Labbe 
21048fe583fSCorentin Labbe static void meson_unregister_algs(struct meson_dev *mc)
21148fe583fSCorentin Labbe {
21248fe583fSCorentin Labbe 	int i;
21348fe583fSCorentin Labbe 
21448fe583fSCorentin Labbe 	for (i = 0; i < ARRAY_SIZE(mc_algs); i++) {
21548fe583fSCorentin Labbe 		if (!mc_algs[i].mc)
21648fe583fSCorentin Labbe 			continue;
21748fe583fSCorentin Labbe 		switch (mc_algs[i].type) {
21848fe583fSCorentin Labbe 		case CRYPTO_ALG_TYPE_SKCIPHER:
21948fe583fSCorentin Labbe 			crypto_unregister_skcipher(&mc_algs[i].alg.skcipher);
22048fe583fSCorentin Labbe 			break;
22148fe583fSCorentin Labbe 		}
22248fe583fSCorentin Labbe 	}
22348fe583fSCorentin Labbe }
22448fe583fSCorentin Labbe 
22548fe583fSCorentin Labbe static int meson_crypto_probe(struct platform_device *pdev)
22648fe583fSCorentin Labbe {
22748fe583fSCorentin Labbe 	struct meson_dev *mc;
22848fe583fSCorentin Labbe 	int err, i;
22948fe583fSCorentin Labbe 
23048fe583fSCorentin Labbe 	if (!pdev->dev.of_node)
23148fe583fSCorentin Labbe 		return -ENODEV;
23248fe583fSCorentin Labbe 
23348fe583fSCorentin Labbe 	mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
23448fe583fSCorentin Labbe 	if (!mc)
23548fe583fSCorentin Labbe 		return -ENOMEM;
23648fe583fSCorentin Labbe 
23748fe583fSCorentin Labbe 	mc->dev = &pdev->dev;
23848fe583fSCorentin Labbe 	platform_set_drvdata(pdev, mc);
23948fe583fSCorentin Labbe 
24048fe583fSCorentin Labbe 	mc->base = devm_platform_ioremap_resource(pdev, 0);
24148fe583fSCorentin Labbe 	if (IS_ERR(mc->base)) {
24248fe583fSCorentin Labbe 		err = PTR_ERR(mc->base);
24348fe583fSCorentin Labbe 		dev_err(&pdev->dev, "Cannot request MMIO err=%d\n", err);
24448fe583fSCorentin Labbe 		return err;
24548fe583fSCorentin Labbe 	}
24648fe583fSCorentin Labbe 	mc->busclk = devm_clk_get(&pdev->dev, "blkmv");
24748fe583fSCorentin Labbe 	if (IS_ERR(mc->busclk)) {
24848fe583fSCorentin Labbe 		err = PTR_ERR(mc->busclk);
24948fe583fSCorentin Labbe 		dev_err(&pdev->dev, "Cannot get core clock err=%d\n", err);
25048fe583fSCorentin Labbe 		return err;
25148fe583fSCorentin Labbe 	}
25248fe583fSCorentin Labbe 
25348fe583fSCorentin Labbe 	mc->irqs = devm_kcalloc(mc->dev, MAXFLOW, sizeof(int), GFP_KERNEL);
25448fe583fSCorentin Labbe 	for (i = 0; i < MAXFLOW; i++) {
25548fe583fSCorentin Labbe 		mc->irqs[i] = platform_get_irq(pdev, i);
25656e0b627STang Bin 		if (mc->irqs[i] < 0)
25748fe583fSCorentin Labbe 			return mc->irqs[i];
25848fe583fSCorentin Labbe 
25948fe583fSCorentin Labbe 		err = devm_request_irq(&pdev->dev, mc->irqs[i], meson_irq_handler, 0,
26048fe583fSCorentin Labbe 				       "gxl-crypto", mc);
26148fe583fSCorentin Labbe 		if (err < 0) {
26248fe583fSCorentin Labbe 			dev_err(mc->dev, "Cannot request IRQ for flow %d\n", i);
26348fe583fSCorentin Labbe 			return err;
26448fe583fSCorentin Labbe 		}
26548fe583fSCorentin Labbe 	}
26648fe583fSCorentin Labbe 
26748fe583fSCorentin Labbe 	err = clk_prepare_enable(mc->busclk);
26848fe583fSCorentin Labbe 	if (err != 0) {
26948fe583fSCorentin Labbe 		dev_err(&pdev->dev, "Cannot prepare_enable busclk\n");
27048fe583fSCorentin Labbe 		return err;
27148fe583fSCorentin Labbe 	}
27248fe583fSCorentin Labbe 
27348fe583fSCorentin Labbe 	err = meson_allocate_chanlist(mc);
27448fe583fSCorentin Labbe 	if (err)
27548fe583fSCorentin Labbe 		goto error_flow;
27648fe583fSCorentin Labbe 
27748fe583fSCorentin Labbe 	err = meson_register_algs(mc);
27848fe583fSCorentin Labbe 	if (err)
27948fe583fSCorentin Labbe 		goto error_alg;
28048fe583fSCorentin Labbe 
28148fe583fSCorentin Labbe #ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
28248fe583fSCorentin Labbe 	mc->dbgfs_dir = debugfs_create_dir("gxl-crypto", NULL);
28348fe583fSCorentin Labbe 	debugfs_create_file("stats", 0444, mc->dbgfs_dir, mc, &meson_debugfs_fops);
28448fe583fSCorentin Labbe #endif
28548fe583fSCorentin Labbe 
28648fe583fSCorentin Labbe 	return 0;
28748fe583fSCorentin Labbe error_alg:
28848fe583fSCorentin Labbe 	meson_unregister_algs(mc);
28948fe583fSCorentin Labbe error_flow:
29024775ac2SCorentin Labbe 	meson_free_chanlist(mc, MAXFLOW - 1);
29148fe583fSCorentin Labbe 	clk_disable_unprepare(mc->busclk);
29248fe583fSCorentin Labbe 	return err;
29348fe583fSCorentin Labbe }
29448fe583fSCorentin Labbe 
29548fe583fSCorentin Labbe static int meson_crypto_remove(struct platform_device *pdev)
29648fe583fSCorentin Labbe {
29748fe583fSCorentin Labbe 	struct meson_dev *mc = platform_get_drvdata(pdev);
29848fe583fSCorentin Labbe 
29948fe583fSCorentin Labbe #ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
30048fe583fSCorentin Labbe 	debugfs_remove_recursive(mc->dbgfs_dir);
30148fe583fSCorentin Labbe #endif
30248fe583fSCorentin Labbe 
30348fe583fSCorentin Labbe 	meson_unregister_algs(mc);
30448fe583fSCorentin Labbe 
30524775ac2SCorentin Labbe 	meson_free_chanlist(mc, MAXFLOW - 1);
30648fe583fSCorentin Labbe 
30748fe583fSCorentin Labbe 	clk_disable_unprepare(mc->busclk);
30848fe583fSCorentin Labbe 	return 0;
30948fe583fSCorentin Labbe }
31048fe583fSCorentin Labbe 
31148fe583fSCorentin Labbe static const struct of_device_id meson_crypto_of_match_table[] = {
31248fe583fSCorentin Labbe 	{ .compatible = "amlogic,gxl-crypto", },
31348fe583fSCorentin Labbe 	{}
31448fe583fSCorentin Labbe };
31548fe583fSCorentin Labbe MODULE_DEVICE_TABLE(of, meson_crypto_of_match_table);
31648fe583fSCorentin Labbe 
31748fe583fSCorentin Labbe static struct platform_driver meson_crypto_driver = {
31848fe583fSCorentin Labbe 	.probe		 = meson_crypto_probe,
31948fe583fSCorentin Labbe 	.remove		 = meson_crypto_remove,
32048fe583fSCorentin Labbe 	.driver		 = {
32148fe583fSCorentin Labbe 		.name		   = "gxl-crypto",
32248fe583fSCorentin Labbe 		.of_match_table	= meson_crypto_of_match_table,
32348fe583fSCorentin Labbe 	},
32448fe583fSCorentin Labbe };
32548fe583fSCorentin Labbe 
32648fe583fSCorentin Labbe module_platform_driver(meson_crypto_driver);
32748fe583fSCorentin Labbe 
32848fe583fSCorentin Labbe MODULE_DESCRIPTION("Amlogic GXL cryptographic offloader");
32948fe583fSCorentin Labbe MODULE_LICENSE("GPL");
33048fe583fSCorentin Labbe MODULE_AUTHOR("Corentin Labbe <clabbe@baylibre.com>");
331