linux/drivers/crypto/rockchip/rk3288_crypto.c
<<
>>
Prefs
   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/module.h>
  14#include <linux/platform_device.h>
  15#include <linux/of.h>
  16#include <linux/clk.h>
  17#include <linux/crypto.h>
  18#include <linux/reset.h>
  19
  20static int rk_crypto_enable_clk(struct rk_crypto_info *dev)
  21{
  22        int err;
  23
  24        err = clk_prepare_enable(dev->sclk);
  25        if (err) {
  26                dev_err(dev->dev, "[%s:%d], Couldn't enable clock sclk\n",
  27                        __func__, __LINE__);
  28                goto err_return;
  29        }
  30        err = clk_prepare_enable(dev->aclk);
  31        if (err) {
  32                dev_err(dev->dev, "[%s:%d], Couldn't enable clock aclk\n",
  33                        __func__, __LINE__);
  34                goto err_aclk;
  35        }
  36        err = clk_prepare_enable(dev->hclk);
  37        if (err) {
  38                dev_err(dev->dev, "[%s:%d], Couldn't enable clock hclk\n",
  39                        __func__, __LINE__);
  40                goto err_hclk;
  41        }
  42        err = clk_prepare_enable(dev->dmaclk);
  43        if (err) {
  44                dev_err(dev->dev, "[%s:%d], Couldn't enable clock dmaclk\n",
  45                        __func__, __LINE__);
  46                goto err_dmaclk;
  47        }
  48        return err;
  49err_dmaclk:
  50        clk_disable_unprepare(dev->hclk);
  51err_hclk:
  52        clk_disable_unprepare(dev->aclk);
  53err_aclk:
  54        clk_disable_unprepare(dev->sclk);
  55err_return:
  56        return err;
  57}
  58
  59static void rk_crypto_disable_clk(struct rk_crypto_info *dev)
  60{
  61        clk_disable_unprepare(dev->dmaclk);
  62        clk_disable_unprepare(dev->hclk);
  63        clk_disable_unprepare(dev->aclk);
  64        clk_disable_unprepare(dev->sclk);
  65}
  66
  67static int check_alignment(struct scatterlist *sg_src,
  68                           struct scatterlist *sg_dst,
  69                           int align_mask)
  70{
  71        int in, out, align;
  72
  73        in = IS_ALIGNED((uint32_t)sg_src->offset, 4) &&
  74             IS_ALIGNED((uint32_t)sg_src->length, align_mask);
  75        if (!sg_dst)
  76                return in;
  77        out = IS_ALIGNED((uint32_t)sg_dst->offset, 4) &&
  78              IS_ALIGNED((uint32_t)sg_dst->length, align_mask);
  79        align = in && out;
  80
  81        return (align && (sg_src->length == sg_dst->length));
  82}
  83
  84static int rk_load_data(struct rk_crypto_info *dev,
  85                        struct scatterlist *sg_src,
  86                        struct scatterlist *sg_dst)
  87{
  88        unsigned int count;
  89
  90        dev->aligned = dev->aligned ?
  91                check_alignment(sg_src, sg_dst, dev->align_size) :
  92                dev->aligned;
  93        if (dev->aligned) {
  94                count = min(dev->left_bytes, sg_src->length);
  95                dev->left_bytes -= count;
  96
  97                if (!dma_map_sg(dev->dev, sg_src, 1, DMA_TO_DEVICE)) {
  98                        dev_err(dev->dev, "[%s:%d] dma_map_sg(src)  error\n",
  99                                __func__, __LINE__);
 100                        return -EINVAL;
 101                }
 102                dev->addr_in = sg_dma_address(sg_src);
 103
 104                if (sg_dst) {
 105                        if (!dma_map_sg(dev->dev, sg_dst, 1, DMA_FROM_DEVICE)) {
 106                                dev_err(dev->dev,
 107                                        "[%s:%d] dma_map_sg(dst)  error\n",
 108                                        __func__, __LINE__);
 109                                dma_unmap_sg(dev->dev, sg_src, 1,
 110                                             DMA_TO_DEVICE);
 111                                return -EINVAL;
 112                        }
 113                        dev->addr_out = sg_dma_address(sg_dst);
 114                }
 115        } else {
 116                count = (dev->left_bytes > PAGE_SIZE) ?
 117                        PAGE_SIZE : dev->left_bytes;
 118
 119                if (!sg_pcopy_to_buffer(dev->first, dev->src_nents,
 120                                        dev->addr_vir, count,
 121                                        dev->total - dev->left_bytes)) {
 122                        dev_err(dev->dev, "[%s:%d] pcopy err\n",
 123                                __func__, __LINE__);
 124                        return -EINVAL;
 125                }
 126                dev->left_bytes -= count;
 127                sg_init_one(&dev->sg_tmp, dev->addr_vir, count);
 128                if (!dma_map_sg(dev->dev, &dev->sg_tmp, 1, DMA_TO_DEVICE)) {
 129                        dev_err(dev->dev, "[%s:%d] dma_map_sg(sg_tmp)  error\n",
 130                                __func__, __LINE__);
 131                        return -ENOMEM;
 132                }
 133                dev->addr_in = sg_dma_address(&dev->sg_tmp);
 134
 135                if (sg_dst) {
 136                        if (!dma_map_sg(dev->dev, &dev->sg_tmp, 1,
 137                                        DMA_FROM_DEVICE)) {
 138                                dev_err(dev->dev,
 139                                        "[%s:%d] dma_map_sg(sg_tmp)  error\n",
 140                                        __func__, __LINE__);
 141                                dma_unmap_sg(dev->dev, &dev->sg_tmp, 1,
 142                                             DMA_TO_DEVICE);
 143                                return -ENOMEM;
 144                        }
 145                        dev->addr_out = sg_dma_address(&dev->sg_tmp);
 146                }
 147        }
 148        dev->count = count;
 149        return 0;
 150}
 151
 152static void rk_unload_data(struct rk_crypto_info *dev)
 153{
 154        struct scatterlist *sg_in, *sg_out;
 155
 156        sg_in = dev->aligned ? dev->sg_src : &dev->sg_tmp;
 157        dma_unmap_sg(dev->dev, sg_in, 1, DMA_TO_DEVICE);
 158
 159        if (dev->sg_dst) {
 160                sg_out = dev->aligned ? dev->sg_dst : &dev->sg_tmp;
 161                dma_unmap_sg(dev->dev, sg_out, 1, DMA_FROM_DEVICE);
 162        }
 163}
 164
 165static irqreturn_t rk_crypto_irq_handle(int irq, void *dev_id)
 166{
 167        struct rk_crypto_info *dev  = platform_get_drvdata(dev_id);
 168        u32 interrupt_status;
 169
 170        spin_lock(&dev->lock);
 171        interrupt_status = CRYPTO_READ(dev, RK_CRYPTO_INTSTS);
 172        CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, interrupt_status);
 173
 174        if (interrupt_status & 0x0a) {
 175                dev_warn(dev->dev, "DMA Error\n");
 176                dev->err = -EFAULT;
 177        }
 178        tasklet_schedule(&dev->done_task);
 179
 180        spin_unlock(&dev->lock);
 181        return IRQ_HANDLED;
 182}
 183
 184static int rk_crypto_enqueue(struct rk_crypto_info *dev,
 185                              struct crypto_async_request *async_req)
 186{
 187        unsigned long flags;
 188        int ret;
 189
 190        spin_lock_irqsave(&dev->lock, flags);
 191        ret = crypto_enqueue_request(&dev->queue, async_req);
 192        if (dev->busy) {
 193                spin_unlock_irqrestore(&dev->lock, flags);
 194                return ret;
 195        }
 196        dev->busy = true;
 197        spin_unlock_irqrestore(&dev->lock, flags);
 198        tasklet_schedule(&dev->queue_task);
 199
 200        return ret;
 201}
 202
 203static void rk_crypto_queue_task_cb(unsigned long data)
 204{
 205        struct rk_crypto_info *dev = (struct rk_crypto_info *)data;
 206        struct crypto_async_request *async_req, *backlog;
 207        unsigned long flags;
 208        int err = 0;
 209
 210        dev->err = 0;
 211        spin_lock_irqsave(&dev->lock, flags);
 212        backlog   = crypto_get_backlog(&dev->queue);
 213        async_req = crypto_dequeue_request(&dev->queue);
 214
 215        if (!async_req) {
 216                dev->busy = false;
 217                spin_unlock_irqrestore(&dev->lock, flags);
 218                return;
 219        }
 220        spin_unlock_irqrestore(&dev->lock, flags);
 221
 222        if (backlog) {
 223                backlog->complete(backlog, -EINPROGRESS);
 224                backlog = NULL;
 225        }
 226
 227        dev->async_req = async_req;
 228        err = dev->start(dev);
 229        if (err)
 230                dev->complete(dev->async_req, err);
 231}
 232
 233static void rk_crypto_done_task_cb(unsigned long data)
 234{
 235        struct rk_crypto_info *dev = (struct rk_crypto_info *)data;
 236
 237        if (dev->err) {
 238                dev->complete(dev->async_req, dev->err);
 239                return;
 240        }
 241
 242        dev->err = dev->update(dev);
 243        if (dev->err)
 244                dev->complete(dev->async_req, dev->err);
 245}
 246
 247static struct rk_crypto_tmp *rk_cipher_algs[] = {
 248        &rk_ecb_aes_alg,
 249        &rk_cbc_aes_alg,
 250        &rk_ecb_des_alg,
 251        &rk_cbc_des_alg,
 252        &rk_ecb_des3_ede_alg,
 253        &rk_cbc_des3_ede_alg,
 254        &rk_ahash_sha1,
 255        &rk_ahash_sha256,
 256        &rk_ahash_md5,
 257};
 258
 259static int rk_crypto_register(struct rk_crypto_info *crypto_info)
 260{
 261        unsigned int i, k;
 262        int err = 0;
 263
 264        for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) {
 265                rk_cipher_algs[i]->dev = crypto_info;
 266                if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER)
 267                        err = crypto_register_skcipher(
 268                                        &rk_cipher_algs[i]->alg.skcipher);
 269                else
 270                        err = crypto_register_ahash(
 271                                        &rk_cipher_algs[i]->alg.hash);
 272                if (err)
 273                        goto err_cipher_algs;
 274        }
 275        return 0;
 276
 277err_cipher_algs:
 278        for (k = 0; k < i; k++) {
 279                if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER)
 280                        crypto_unregister_skcipher(&rk_cipher_algs[k]->alg.skcipher);
 281                else
 282                        crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash);
 283        }
 284        return err;
 285}
 286
 287static void rk_crypto_unregister(void)
 288{
 289        unsigned int i;
 290
 291        for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) {
 292                if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER)
 293                        crypto_unregister_skcipher(&rk_cipher_algs[i]->alg.skcipher);
 294                else
 295                        crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash);
 296        }
 297}
 298
 299static void rk_crypto_action(void *data)
 300{
 301        struct rk_crypto_info *crypto_info = data;
 302
 303        reset_control_assert(crypto_info->rst);
 304}
 305
 306static const struct of_device_id crypto_of_id_table[] = {
 307        { .compatible = "rockchip,rk3288-crypto" },
 308        {}
 309};
 310MODULE_DEVICE_TABLE(of, crypto_of_id_table);
 311
 312static int rk_crypto_probe(struct platform_device *pdev)
 313{
 314        struct device *dev = &pdev->dev;
 315        struct rk_crypto_info *crypto_info;
 316        int err = 0;
 317
 318        crypto_info = devm_kzalloc(&pdev->dev,
 319                                   sizeof(*crypto_info), GFP_KERNEL);
 320        if (!crypto_info) {
 321                err = -ENOMEM;
 322                goto err_crypto;
 323        }
 324
 325        crypto_info->rst = devm_reset_control_get(dev, "crypto-rst");
 326        if (IS_ERR(crypto_info->rst)) {
 327                err = PTR_ERR(crypto_info->rst);
 328                goto err_crypto;
 329        }
 330
 331        reset_control_assert(crypto_info->rst);
 332        usleep_range(10, 20);
 333        reset_control_deassert(crypto_info->rst);
 334
 335        err = devm_add_action_or_reset(dev, rk_crypto_action, crypto_info);
 336        if (err)
 337                goto err_crypto;
 338
 339        spin_lock_init(&crypto_info->lock);
 340
 341        crypto_info->reg = devm_platform_ioremap_resource(pdev, 0);
 342        if (IS_ERR(crypto_info->reg)) {
 343                err = PTR_ERR(crypto_info->reg);
 344                goto err_crypto;
 345        }
 346
 347        crypto_info->aclk = devm_clk_get(&pdev->dev, "aclk");
 348        if (IS_ERR(crypto_info->aclk)) {
 349                err = PTR_ERR(crypto_info->aclk);
 350                goto err_crypto;
 351        }
 352
 353        crypto_info->hclk = devm_clk_get(&pdev->dev, "hclk");
 354        if (IS_ERR(crypto_info->hclk)) {
 355                err = PTR_ERR(crypto_info->hclk);
 356                goto err_crypto;
 357        }
 358
 359        crypto_info->sclk = devm_clk_get(&pdev->dev, "sclk");
 360        if (IS_ERR(crypto_info->sclk)) {
 361                err = PTR_ERR(crypto_info->sclk);
 362                goto err_crypto;
 363        }
 364
 365        crypto_info->dmaclk = devm_clk_get(&pdev->dev, "apb_pclk");
 366        if (IS_ERR(crypto_info->dmaclk)) {
 367                err = PTR_ERR(crypto_info->dmaclk);
 368                goto err_crypto;
 369        }
 370
 371        crypto_info->irq = platform_get_irq(pdev, 0);
 372        if (crypto_info->irq < 0) {
 373                dev_warn(crypto_info->dev,
 374                         "control Interrupt is not available.\n");
 375                err = crypto_info->irq;
 376                goto err_crypto;
 377        }
 378
 379        err = devm_request_irq(&pdev->dev, crypto_info->irq,
 380                               rk_crypto_irq_handle, IRQF_SHARED,
 381                               "rk-crypto", pdev);
 382
 383        if (err) {
 384                dev_err(crypto_info->dev, "irq request failed.\n");
 385                goto err_crypto;
 386        }
 387
 388        crypto_info->dev = &pdev->dev;
 389        platform_set_drvdata(pdev, crypto_info);
 390
 391        tasklet_init(&crypto_info->queue_task,
 392                     rk_crypto_queue_task_cb, (unsigned long)crypto_info);
 393        tasklet_init(&crypto_info->done_task,
 394                     rk_crypto_done_task_cb, (unsigned long)crypto_info);
 395        crypto_init_queue(&crypto_info->queue, 50);
 396
 397        crypto_info->enable_clk = rk_crypto_enable_clk;
 398        crypto_info->disable_clk = rk_crypto_disable_clk;
 399        crypto_info->load_data = rk_load_data;
 400        crypto_info->unload_data = rk_unload_data;
 401        crypto_info->enqueue = rk_crypto_enqueue;
 402        crypto_info->busy = false;
 403
 404        err = rk_crypto_register(crypto_info);
 405        if (err) {
 406                dev_err(dev, "err in register alg");
 407                goto err_register_alg;
 408        }
 409
 410        dev_info(dev, "Crypto Accelerator successfully registered\n");
 411        return 0;
 412
 413err_register_alg:
 414        tasklet_kill(&crypto_info->queue_task);
 415        tasklet_kill(&crypto_info->done_task);
 416err_crypto:
 417        return err;
 418}
 419
 420static int rk_crypto_remove(struct platform_device *pdev)
 421{
 422        struct rk_crypto_info *crypto_tmp = platform_get_drvdata(pdev);
 423
 424        rk_crypto_unregister();
 425        tasklet_kill(&crypto_tmp->done_task);
 426        tasklet_kill(&crypto_tmp->queue_task);
 427        return 0;
 428}
 429
 430static struct platform_driver crypto_driver = {
 431        .probe          = rk_crypto_probe,
 432        .remove         = rk_crypto_remove,
 433        .driver         = {
 434                .name   = "rk3288-crypto",
 435                .of_match_table = crypto_of_id_table,
 436        },
 437};
 438
 439module_platform_driver(crypto_driver);
 440
 441MODULE_AUTHOR("Zain Wang <zain.wang@rock-chips.com>");
 442MODULE_DESCRIPTION("Support for Rockchip's cryptographic engine");
 443MODULE_LICENSE("GPL");
 444