firmware/br-ext-chip-ingenic/board/t40/kernel/patches/00000-drivers_misc_ingenic_...

488 lines
12 KiB
Diff

diff -drupN a/drivers/misc/ingenic_rsa.c b/drivers/misc/ingenic_rsa.c
--- a/drivers/misc/ingenic_rsa.c 1970-01-01 03:00:00.000000000 +0300
+++ b/drivers/misc/ingenic_rsa.c 2022-06-09 05:02:30.000000000 +0300
@@ -0,0 +1,483 @@
+/*
+ * drivers/misc/ingenic_rsa.c - Ingenic rsa driver
+ *
+ * Copyright (C) 2012 Ingenic Semiconductor Co., Ltd.
+ * Author: mayuanjun <yuanjun.ma@ingenic.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#define MAX_KEY_LEN_WORD 64
+#define DEV_NAME "rsa"
+
+#define MCU_BOOT_DDR 0xb3422000
+
+#define DRV_NAME "jz-rsa"
+#define MAX_KEY_LEN_WORD 64
+
+struct jz_rsa {
+ struct miscdevice mdev;
+ struct device *dev;
+
+ struct clk *clk_gate;
+ void __iomem *iomem;
+ unsigned int irq;
+
+ bool busy;
+
+ struct mutex mutex;
+
+ wait_queue_head_t wq;
+
+ unsigned int n_len;
+ unsigned int per_done;
+ unsigned int rsa_done;
+};
+
+struct rsa_key {
+ unsigned int *e;
+ unsigned int *n;
+ unsigned int rsa_mode;
+};
+
+struct rsa_data {
+ unsigned int *input;
+ unsigned int inlen;
+ unsigned int *output;
+};
+
+#define RSA_PERPARE_KEY 0x1
+#define RSA_DO_CRYPT 0x2
+
+#define RSAC 0x0
+#define RSAE 0x4
+#define RSAN 0x8
+#define RSAM 0xc
+#define RSAP 0x10
+
+#define RSAC_RSA_INT_M (1 << 17)
+#define RSAC_PER_INT_M (1 << 16)
+#define RSAC_RSA_2048 (1 << 7)
+#define RSAC_RSAC (1 << 6)
+#define RSAC_RSAD (1 << 5)
+#define RSAC_RSAS (1 << 4)
+#define RSAC_PERC (1 << 3)
+#define RSAC_PERD (1 << 2)
+#define RSAC_PERS (1 << 1)
+#define RSAC_EN (1 << 0)
+
+#define mcu_boot() \
+ do { \
+ *(volatile unsigned int *)0xb3421030 &= ~1; \
+ } while(0)
+
+#define mcu_reset() \
+ do { \
+ *(volatile unsigned int *)0xb3421030 |= 1; \
+ } while(0)
+
+static int inline rsa_readl(struct jz_rsa *rsa, unsigned int offset)
+{
+ return readl(rsa->iomem + offset);
+}
+
+static void inline rsa_writel(struct jz_rsa *rsa, unsigned int offset, unsigned int val)
+{
+ writel(val, rsa->iomem + offset);
+}
+
+static int rsa_perpare_key(struct jz_rsa *rsa, struct rsa_key *rsa_key)
+{
+ unsigned int n[MAX_KEY_LEN_WORD];
+ unsigned int e[MAX_KEY_LEN_WORD];
+ unsigned int keylen = rsa_key->rsa_mode/32;
+
+ unsigned int tmp;
+ unsigned int i;
+ int ret = 0;
+
+ mutex_lock(&rsa->mutex);
+
+ rsa->per_done = 0;
+ rsa->n_len = keylen;
+
+ if(copy_from_user(e, rsa_key->e, keylen * 4)) {
+ dev_err(rsa->dev, "Failed to copy rsa_key->e form user!\n");
+ ret = -EFAULT;
+ goto err;
+ }
+ if(copy_from_user(n, rsa_key->n, keylen * 4)) {
+ dev_err(rsa->dev, "Failed to copy rsa_key->n form user!\n");
+ ret = -EFAULT;
+ goto err;
+ }
+
+ tmp = rsa_readl(rsa, RSAC);
+ if(rsa_key->rsa_mode == 2048)
+ tmp |= RSAC_RSA_2048;
+ else if (rsa_key->rsa_mode == 1024)
+ tmp &= ~RSAC_RSA_2048;
+ tmp &= ~RSAC_PER_INT_M;
+ rsa_writel(rsa, RSAC, tmp);
+
+ for(i = 0; i < keylen; i++) {
+ rsa_writel(rsa, RSAE, e[i]);
+ }
+ for(i = 0; i < keylen; i++){
+ rsa_writel(rsa, RSAN, n[i]);
+ }
+ rsa_writel(rsa, RSAC, RSAC_PERS | rsa_readl(rsa, RSAC));
+
+ ret = wait_event_interruptible(rsa->wq, rsa->per_done == 1);
+ if(ret < 0) {
+ dev_err(rsa->dev, "key perpare can't wait irq\n");
+ ret = -EFAULT;
+ goto err;
+ }
+
+ rsa_writel(rsa, RSAC, RSAC_PERC | rsa_readl(rsa, RSAC));
+ rsa_writel(rsa, RSAC, ~RSAC_PERC & rsa_readl(rsa, RSAC));
+
+ mutex_unlock(&rsa->mutex);
+ return 0;
+
+err:
+ mutex_unlock(&rsa->mutex);
+ return ret;
+}
+
+static int rsa_do_crypt(struct jz_rsa *rsa, struct rsa_data *rsa_data)
+{
+ unsigned int input[MAX_KEY_LEN_WORD];
+ unsigned int output[MAX_KEY_LEN_WORD];
+ unsigned int *id = rsa_data->input;
+ unsigned int *od = rsa_data->output;
+ unsigned int keylen = rsa->n_len;
+ unsigned int len = rsa_data->inlen;
+
+ unsigned int i;
+ int ret = 0;
+
+ mutex_lock(&rsa->mutex);
+
+ if(len % keylen) {
+ pr_err("Data len err \n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ while(len > 0) {
+
+ rsa->rsa_done = 0;
+
+ if(copy_from_user(input, id, keylen * 4)) {
+ dev_err(rsa->dev, "Failed to copy rsa_data->input form user!\n");
+ ret = -EFAULT;
+ goto err;
+ }
+
+ for(i = 0; i < keylen; i++) {
+ rsa_writel(rsa, RSAM, input[i]);
+ }
+
+ rsa_writel(rsa, RSAC, ~RSAC_RSA_INT_M & rsa_readl(rsa, RSAC));
+ rsa_writel(rsa, RSAC, RSAC_RSAS | rsa_readl(rsa, RSAC));
+
+ ret = wait_event_interruptible(rsa->wq, rsa->rsa_done == 1);
+ if(ret < 0) {
+ dev_err(rsa->dev, "rsa crypt can't wait irq\n");
+ ret = -EFAULT;
+ goto err;
+ }
+
+ for(i = 0; i < keylen; i++) {
+ output[keylen -1 - i] = rsa_readl(rsa, RSAP);
+ }
+
+ rsa_writel(rsa, RSAC, rsa_readl(rsa, RSAC) | RSAC_RSAC);
+ rsa_writel(rsa, RSAC, rsa_readl(rsa, RSAC) & ~RSAC_RSAC);
+
+ if(copy_to_user(od, output, keylen * 4)) {
+ dev_err(rsa->dev, "Failed to copy rsa_data->input form user!\n");
+ ret = -EFAULT;
+ goto err;
+ }
+
+ len -= keylen;
+ id += keylen;
+ od += keylen;
+
+ }
+
+ mutex_unlock(&rsa->mutex);
+ return 0;
+
+err:
+ mutex_unlock(&rsa->mutex);
+ return ret;
+
+}
+
+static int rsa_open(struct inode *inode, struct file *flip)
+{
+ struct miscdevice *mdev = flip->private_data;
+ struct jz_rsa *rsa = container_of(mdev, struct jz_rsa, mdev);
+ int tmp;
+
+ mutex_lock(&rsa->mutex);
+ if(rsa->busy) {
+ dev_err(rsa->dev, "Device is busy!\n");
+ mutex_unlock(&rsa->mutex);
+ return -EBUSY;
+ }
+
+ rsa->busy = 1;
+
+ rsa_writel(rsa, RSAC, RSAC_EN | rsa_readl(rsa, RSAC));
+
+ mutex_unlock(&rsa->mutex);
+
+ return 0;
+}
+
+static int rsa_release(struct inode *inode, struct file *flip)
+{
+ struct miscdevice *mdev = flip->private_data;
+ struct jz_rsa *rsa = container_of(mdev, struct jz_rsa, mdev);
+
+ mutex_lock(&rsa->mutex);
+
+ rsa->busy = 0;
+
+ rsa_writel(rsa, RSAC, ~RSAC_EN & rsa_readl(rsa, RSAC));
+
+ mutex_unlock(&rsa->mutex);
+
+ return 0;
+}
+
+static long rsa_ioctl(struct file *flip, unsigned int cmd, unsigned long args)
+{
+ struct miscdevice *mdev = flip->private_data;
+ struct jz_rsa *rsa = container_of(mdev, struct jz_rsa, mdev);
+ struct rsa_key rsa_key;
+ struct rsa_data rsa_data;
+ int ret = 0;
+
+ switch (cmd) {
+ case RSA_PERPARE_KEY:
+
+ if(copy_from_user(&rsa_key, (void *)args, sizeof(struct rsa_key))) {
+ dev_err(rsa->dev, "Failed to copy rsa_key form user!\n");
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = rsa_perpare_key(rsa, &rsa_key);
+
+ break;
+ case RSA_DO_CRYPT:
+ if(rsa->n_len != 32 && rsa->n_len != 64) {
+ dev_err(rsa->dev, "RSA key len err!\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ if(copy_from_user(&rsa_data, (void *)args, sizeof(struct rsa_data))) {
+ dev_err(rsa->dev, "Could not copy data from user!\n");
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = rsa_do_crypt(rsa, &rsa_data);
+ if(ret < 0) {
+ dev_err(rsa->dev, "Failed to crypt data!\n");
+ goto err;
+ }
+
+ break;
+ default:
+ dev_err(rsa->dev, "Unsupport IO cmd: %x\n", cmd);
+
+ }
+
+ return 0;
+err:
+ return ret;
+}
+
+static struct file_operations rsa_misc_fops = {
+ .owner = THIS_MODULE,
+ .open = rsa_open,
+ .release = rsa_release,
+ .unlocked_ioctl = rsa_ioctl,
+};
+
+static irqreturn_t rsa_irq(int irq, void *data)
+{
+ struct jz_rsa *rsa = (struct jz_rsa *)data;
+
+ if (rsa_readl(rsa, RSAC) & RSAC_RSAD) {
+ rsa_writel(rsa, RSAC, ~RSAC_RSAS & rsa_readl(rsa, RSAC));
+ rsa_writel(rsa, RSAC, RSAC_RSA_INT_M | rsa_readl(rsa, RSAC));
+ rsa->rsa_done = 1;
+ } else if (rsa_readl(rsa, RSAC) & RSAC_PERD) {
+ rsa_writel(rsa, RSAC, ~RSAC_PERS & rsa_readl(rsa, RSAC));
+ rsa_writel(rsa, RSAC, RSAC_PER_INT_M | rsa_readl(rsa, RSAC));
+ rsa->per_done = 1;
+ }
+
+ wake_up(&rsa->wq);
+
+ return IRQ_HANDLED;
+}
+
+#define cpm_readl(o) (*(volatile unsigned int *)(o))
+#define cpm_writel(b, o) (*(volatile unsigned int *)(o)) = (b)
+#define CPM_RSACDR (0xb0000050)
+#define CPM_CLKGR0 (0xb0000020)
+static int jz_rsa_probe(struct platform_device * pdev)
+{
+ int ret = 0;
+ struct jz_rsa *rsa;
+ struct resource *res;
+ unsigned int tmp;
+
+ rsa = kzalloc(sizeof(struct jz_rsa), GFP_KERNEL);
+ if(IS_ERR_OR_NULL(rsa)) {
+ pr_err("Failed to alloc mem fir jz_rsa!\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ rsa->dev = &pdev->dev;
+
+ rsa->clk_gate = devm_clk_get(&pdev->dev, "gate_rsa");
+ if (IS_ERR(rsa->clk_gate)) {
+ dev_err(&pdev->dev, "cannot find rsa clock\n");
+ ret = PTR_ERR(rsa->clk_gate);
+ goto err1;
+ }
+ clk_prepare_enable(rsa->clk_gate);
+
+ /* rsa cguclk SACLK/2 */
+ tmp = cpm_readl(CPM_RSACDR);
+ tmp &= ~(2<<30 | 0xf | 1 << 27);
+ tmp |= 1 << 29;
+ tmp |= 2 << 0;
+
+ cpm_writel(tmp, CPM_RSACDR);
+ while(cpm_readl(CPM_RSACDR) & (1<<28));
+ tmp &= ~(1<<29);
+ cpm_writel(tmp, CPM_RSACDR);
+ cpm_writel(0, CPM_CLKGR0);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if(IS_ERR_OR_NULL(res)) {
+ dev_err(rsa->dev, "No iomem resource!\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ rsa->irq = platform_get_irq(pdev, 0);
+ if(rsa->irq < 0) {
+ dev_err(&pdev->dev, "No irq resource!\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ rsa->iomem = devm_ioremap(rsa->dev, res->start, resource_size(res));
+ if(IS_ERR_OR_NULL(rsa->iomem)) {
+ dev_err(&pdev->dev, "Failed to remap io resources!\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ ret = devm_request_irq(&pdev->dev, rsa->irq, rsa_irq, IRQF_ONESHOT, dev_name(&pdev->dev), rsa);
+ if(ret < 0) {
+ dev_err(&pdev->dev, "Failed to request irq!\n");
+ goto err_request_irq;
+ }
+
+ init_waitqueue_head(&rsa->wq);
+
+ platform_set_drvdata(pdev, rsa);
+
+ mutex_init(&rsa->mutex);
+
+ rsa->mdev.minor = MISC_DYNAMIC_MINOR;
+ rsa->mdev.name = DEV_NAME;
+ rsa->mdev.fops = &rsa_misc_fops;
+ ret = misc_register(&rsa->mdev);
+ if(ret < 0) {
+ dev_err(&pdev->dev, "Failed to register misc driver!\n");
+ goto err_misc_register;
+ }
+
+ dev_info(&pdev->dev, "rsa driver probe ok!\n");
+
+ return 0;
+
+err_misc_register:
+ mutex_destroy(&rsa->mutex);
+err_request_irq:
+ devm_iounmap(rsa->dev, rsa->iomem);
+err1:
+ kfree(rsa);
+err:
+ dev_err(rsa->dev, "initialization failed.\n");
+ return ret;
+
+}
+
+static int jz_rsa_remove(struct platform_device *pdev)
+{
+ struct jz_rsa *rsa = platform_get_drvdata(pdev);
+
+ misc_deregister(&rsa->mdev);
+ devm_iounmap(rsa->dev, rsa->iomem);
+ kfree(rsa);
+
+ return 0;
+}
+
+static const struct of_device_id ingenic_rsa_dt_match[] = {
+ { .compatible = "ingenic,rsa", .data = NULL },
+ {},
+};
+MODULE_DEVICE_TABLE(of, aic_dt_match);
+
+static struct platform_driver ingenic_rsa_driver = {
+ .probe = jz_rsa_probe,
+ .remove = jz_rsa_remove,
+ .driver = {
+ .name = "rsa",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(ingenic_rsa_dt_match),
+ },
+};
+
+module_platform_driver(ingenic_rsa_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("mayuanjun <yuanjun.ma@ingenic.com>");
+MODULE_DESCRIPTION("ingenic rsa driver");