linux/drivers/crypto/amlogic/amlogic-gxl-core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * amlgoic-core.c - hardware cryptographic offloader for Amlogic GXL SoC
   4 *
   5 * Copyright (C) 2018-2019 Corentin Labbe <clabbe@baylibre.com>
   6 *
   7 * Core file which registers crypto algorithms supported by the hardware.
   8 */
   9#include <linux/clk.h>
  10#include <linux/crypto.h>
  11#include <linux/io.h>
  12#include <linux/interrupt.h>
  13#include <linux/irq.h>
  14#include <linux/module.h>
  15#include <linux/of.h>
  16#include <linux/of_device.h>
  17#include <linux/platform_device.h>
  18#include <crypto/internal/skcipher.h>
  19#include <linux/dma-mapping.h>
  20
  21#include "amlogic-gxl.h"
  22
  23static irqreturn_t meson_irq_handler(int irq, void *data)
  24{
  25        struct meson_dev *mc = (struct meson_dev *)data;
  26        int flow;
  27        u32 p;
  28
  29        for (flow = 0; flow < MAXFLOW; flow++) {
  30                if (mc->irqs[flow] == irq) {
  31                        p = readl(mc->base + ((0x04 + flow) << 2));
  32                        if (p) {
  33                                writel_relaxed(0xF, mc->base + ((0x4 + flow) << 2));
  34                                mc->chanlist[flow].status = 1;
  35                                complete(&mc->chanlist[flow].complete);
  36                                return IRQ_HANDLED;
  37                        }
  38                        dev_err(mc->dev, "%s %d Got irq for flow %d but ctrl is empty\n", __func__, irq, flow);
  39                }
  40        }
  41
  42        dev_err(mc->dev, "%s %d from unknown irq\n", __func__, irq);
  43        return IRQ_HANDLED;
  44}
  45
  46static struct meson_alg_template mc_algs[] = {
  47{
  48        .type = CRYPTO_ALG_TYPE_SKCIPHER,
  49        .blockmode = MESON_OPMODE_CBC,
  50        .alg.skcipher = {
  51                .base = {
  52                        .cra_name = "cbc(aes)",
  53                        .cra_driver_name = "cbc-aes-gxl",
  54                        .cra_priority = 400,
  55                        .cra_blocksize = AES_BLOCK_SIZE,
  56                        .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |
  57                                CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |
  58                                CRYPTO_ALG_NEED_FALLBACK,
  59                        .cra_ctxsize = sizeof(struct meson_cipher_tfm_ctx),
  60                        .cra_module = THIS_MODULE,
  61                        .cra_alignmask = 0xf,
  62                        .cra_init = meson_cipher_init,
  63                        .cra_exit = meson_cipher_exit,
  64                },
  65                .min_keysize    = AES_MIN_KEY_SIZE,
  66                .max_keysize    = AES_MAX_KEY_SIZE,
  67                .ivsize         = AES_BLOCK_SIZE,
  68                .setkey         = meson_aes_setkey,
  69                .encrypt        = meson_skencrypt,
  70                .decrypt        = meson_skdecrypt,
  71        }
  72},
  73{
  74        .type = CRYPTO_ALG_TYPE_SKCIPHER,
  75        .blockmode = MESON_OPMODE_ECB,
  76        .alg.skcipher = {
  77                .base = {
  78                        .cra_name = "ecb(aes)",
  79                        .cra_driver_name = "ecb-aes-gxl",
  80                        .cra_priority = 400,
  81                        .cra_blocksize = AES_BLOCK_SIZE,
  82                        .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |
  83                                CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |
  84                                CRYPTO_ALG_NEED_FALLBACK,
  85                        .cra_ctxsize = sizeof(struct meson_cipher_tfm_ctx),
  86                        .cra_module = THIS_MODULE,
  87                        .cra_alignmask = 0xf,
  88                        .cra_init = meson_cipher_init,
  89                        .cra_exit = meson_cipher_exit,
  90                },
  91                .min_keysize    = AES_MIN_KEY_SIZE,
  92                .max_keysize    = AES_MAX_KEY_SIZE,
  93                .setkey         = meson_aes_setkey,
  94                .encrypt        = meson_skencrypt,
  95                .decrypt        = meson_skdecrypt,
  96        }
  97},
  98};
  99
 100#ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
 101static int meson_debugfs_show(struct seq_file *seq, void *v)
 102{
 103        struct meson_dev *mc = seq->private;
 104        int i;
 105
 106        for (i = 0; i < MAXFLOW; i++)
 107                seq_printf(seq, "Channel %d: nreq %lu\n", i, mc->chanlist[i].stat_req);
 108
 109        for (i = 0; i < ARRAY_SIZE(mc_algs); i++) {
 110                switch (mc_algs[i].type) {
 111                case CRYPTO_ALG_TYPE_SKCIPHER:
 112                        seq_printf(seq, "%s %s %lu %lu\n",
 113                                   mc_algs[i].alg.skcipher.base.cra_driver_name,
 114                                   mc_algs[i].alg.skcipher.base.cra_name,
 115                                   mc_algs[i].stat_req, mc_algs[i].stat_fb);
 116                        break;
 117                }
 118        }
 119        return 0;
 120}
 121DEFINE_SHOW_ATTRIBUTE(meson_debugfs);
 122#endif
 123
 124static void meson_free_chanlist(struct meson_dev *mc, int i)
 125{
 126        while (i >= 0) {
 127                crypto_engine_exit(mc->chanlist[i].engine);
 128                if (mc->chanlist[i].tl)
 129                        dma_free_coherent(mc->dev, sizeof(struct meson_desc) * MAXDESC,
 130                                          mc->chanlist[i].tl,
 131                                          mc->chanlist[i].t_phy);
 132                i--;
 133        }
 134}
 135
 136/*
 137 * Allocate the channel list structure
 138 */
 139static int meson_allocate_chanlist(struct meson_dev *mc)
 140{
 141        int i, err;
 142
 143        mc->chanlist = devm_kcalloc(mc->dev, MAXFLOW,
 144                                    sizeof(struct meson_flow), GFP_KERNEL);
 145        if (!mc->chanlist)
 146                return -ENOMEM;
 147
 148        for (i = 0; i < MAXFLOW; i++) {
 149                init_completion(&mc->chanlist[i].complete);
 150
 151                mc->chanlist[i].engine = crypto_engine_alloc_init(mc->dev, true);
 152                if (!mc->chanlist[i].engine) {
 153                        dev_err(mc->dev, "Cannot allocate engine\n");
 154                        i--;
 155                        err = -ENOMEM;
 156                        goto error_engine;
 157                }
 158                err = crypto_engine_start(mc->chanlist[i].engine);
 159                if (err) {
 160                        dev_err(mc->dev, "Cannot start engine\n");
 161                        goto error_engine;
 162                }
 163                mc->chanlist[i].tl = dma_alloc_coherent(mc->dev,
 164                                                        sizeof(struct meson_desc) * MAXDESC,
 165                                                        &mc->chanlist[i].t_phy,
 166                                                        GFP_KERNEL);
 167                if (!mc->chanlist[i].tl) {
 168                        err = -ENOMEM;
 169                        goto error_engine;
 170                }
 171        }
 172        return 0;
 173error_engine:
 174        meson_free_chanlist(mc, i);
 175        return err;
 176}
 177
 178static int meson_register_algs(struct meson_dev *mc)
 179{
 180        int err, i;
 181
 182        for (i = 0; i < ARRAY_SIZE(mc_algs); i++) {
 183                mc_algs[i].mc = mc;
 184                switch (mc_algs[i].type) {
 185                case CRYPTO_ALG_TYPE_SKCIPHER:
 186                        err = crypto_register_skcipher(&mc_algs[i].alg.skcipher);
 187                        if (err) {
 188                                dev_err(mc->dev, "Fail to register %s\n",
 189                                        mc_algs[i].alg.skcipher.base.cra_name);
 190                                mc_algs[i].mc = NULL;
 191                                return err;
 192                        }
 193                        break;
 194                }
 195        }
 196
 197        return 0;
 198}
 199
 200static void meson_unregister_algs(struct meson_dev *mc)
 201{
 202        int i;
 203
 204        for (i = 0; i < ARRAY_SIZE(mc_algs); i++) {
 205                if (!mc_algs[i].mc)
 206                        continue;
 207                switch (mc_algs[i].type) {
 208                case CRYPTO_ALG_TYPE_SKCIPHER:
 209                        crypto_unregister_skcipher(&mc_algs[i].alg.skcipher);
 210                        break;
 211                }
 212        }
 213}
 214
 215static int meson_crypto_probe(struct platform_device *pdev)
 216{
 217        struct meson_dev *mc;
 218        int err, i;
 219
 220        mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
 221        if (!mc)
 222                return -ENOMEM;
 223
 224        mc->dev = &pdev->dev;
 225        platform_set_drvdata(pdev, mc);
 226
 227        mc->base = devm_platform_ioremap_resource(pdev, 0);
 228        if (IS_ERR(mc->base)) {
 229                err = PTR_ERR(mc->base);
 230                dev_err(&pdev->dev, "Cannot request MMIO err=%d\n", err);
 231                return err;
 232        }
 233        mc->busclk = devm_clk_get(&pdev->dev, "blkmv");
 234        if (IS_ERR(mc->busclk)) {
 235                err = PTR_ERR(mc->busclk);
 236                dev_err(&pdev->dev, "Cannot get core clock err=%d\n", err);
 237                return err;
 238        }
 239
 240        mc->irqs = devm_kcalloc(mc->dev, MAXFLOW, sizeof(int), GFP_KERNEL);
 241        for (i = 0; i < MAXFLOW; i++) {
 242                mc->irqs[i] = platform_get_irq(pdev, i);
 243                if (mc->irqs[i] < 0)
 244                        return mc->irqs[i];
 245
 246                err = devm_request_irq(&pdev->dev, mc->irqs[i], meson_irq_handler, 0,
 247                                       "gxl-crypto", mc);
 248                if (err < 0) {
 249                        dev_err(mc->dev, "Cannot request IRQ for flow %d\n", i);
 250                        return err;
 251                }
 252        }
 253
 254        err = clk_prepare_enable(mc->busclk);
 255        if (err != 0) {
 256                dev_err(&pdev->dev, "Cannot prepare_enable busclk\n");
 257                return err;
 258        }
 259
 260        err = meson_allocate_chanlist(mc);
 261        if (err)
 262                goto error_flow;
 263
 264        err = meson_register_algs(mc);
 265        if (err)
 266                goto error_alg;
 267
 268#ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
 269        mc->dbgfs_dir = debugfs_create_dir("gxl-crypto", NULL);
 270        debugfs_create_file("stats", 0444, mc->dbgfs_dir, mc, &meson_debugfs_fops);
 271#endif
 272
 273        return 0;
 274error_alg:
 275        meson_unregister_algs(mc);
 276error_flow:
 277        meson_free_chanlist(mc, MAXFLOW - 1);
 278        clk_disable_unprepare(mc->busclk);
 279        return err;
 280}
 281
 282static int meson_crypto_remove(struct platform_device *pdev)
 283{
 284        struct meson_dev *mc = platform_get_drvdata(pdev);
 285
 286#ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
 287        debugfs_remove_recursive(mc->dbgfs_dir);
 288#endif
 289
 290        meson_unregister_algs(mc);
 291
 292        meson_free_chanlist(mc, MAXFLOW - 1);
 293
 294        clk_disable_unprepare(mc->busclk);
 295        return 0;
 296}
 297
 298static const struct of_device_id meson_crypto_of_match_table[] = {
 299        { .compatible = "amlogic,gxl-crypto", },
 300        {}
 301};
 302MODULE_DEVICE_TABLE(of, meson_crypto_of_match_table);
 303
 304static struct platform_driver meson_crypto_driver = {
 305        .probe           = meson_crypto_probe,
 306        .remove          = meson_crypto_remove,
 307        .driver          = {
 308                .name              = "gxl-crypto",
 309                .of_match_table = meson_crypto_of_match_table,
 310        },
 311};
 312
 313module_platform_driver(meson_crypto_driver);
 314
 315MODULE_DESCRIPTION("Amlogic GXL cryptographic offloader");
 316MODULE_LICENSE("GPL");
 317MODULE_AUTHOR("Corentin Labbe <clabbe@baylibre.com>");
 318