1ebc82efaSNicolas Royer /* 2ebc82efaSNicolas Royer * Cryptographic API. 3ebc82efaSNicolas Royer * 4ebc82efaSNicolas Royer * Support for ATMEL SHA1/SHA256 HW acceleration. 5ebc82efaSNicolas Royer * 6ebc82efaSNicolas Royer * Copyright (c) 2012 Eukréa Electromatique - ATMEL 7ebc82efaSNicolas Royer * Author: Nicolas Royer <nicolas@eukrea.com> 8ebc82efaSNicolas Royer * 9ebc82efaSNicolas Royer * This program is free software; you can redistribute it and/or modify 10ebc82efaSNicolas Royer * it under the terms of the GNU General Public License version 2 as published 11ebc82efaSNicolas Royer * by the Free Software Foundation. 12ebc82efaSNicolas Royer * 13ebc82efaSNicolas Royer * Some ideas are from omap-sham.c drivers. 14ebc82efaSNicolas Royer */ 15ebc82efaSNicolas Royer 16ebc82efaSNicolas Royer 17ebc82efaSNicolas Royer #include <linux/kernel.h> 18ebc82efaSNicolas Royer #include <linux/module.h> 19ebc82efaSNicolas Royer #include <linux/slab.h> 20ebc82efaSNicolas Royer #include <linux/err.h> 21ebc82efaSNicolas Royer #include <linux/clk.h> 22ebc82efaSNicolas Royer #include <linux/io.h> 23ebc82efaSNicolas Royer #include <linux/hw_random.h> 24ebc82efaSNicolas Royer #include <linux/platform_device.h> 25ebc82efaSNicolas Royer 26ebc82efaSNicolas Royer #include <linux/device.h> 27ebc82efaSNicolas Royer #include <linux/init.h> 28ebc82efaSNicolas Royer #include <linux/errno.h> 29ebc82efaSNicolas Royer #include <linux/interrupt.h> 30ebc82efaSNicolas Royer #include <linux/irq.h> 31ebc82efaSNicolas Royer #include <linux/scatterlist.h> 32ebc82efaSNicolas Royer #include <linux/dma-mapping.h> 33abfe7ae4SNicolas Ferre #include <linux/of_device.h> 34ebc82efaSNicolas Royer #include <linux/delay.h> 35ebc82efaSNicolas Royer #include <linux/crypto.h> 36ebc82efaSNicolas Royer #include <linux/cryptohash.h> 37ebc82efaSNicolas Royer #include <crypto/scatterwalk.h> 38ebc82efaSNicolas Royer #include <crypto/algapi.h> 39ebc82efaSNicolas Royer #include <crypto/sha.h> 40ebc82efaSNicolas Royer #include <crypto/hash.h> 41ebc82efaSNicolas Royer #include <crypto/internal/hash.h> 42d4905b38SNicolas Royer #include <linux/platform_data/crypto-atmel.h> 43ebc82efaSNicolas Royer #include "atmel-sha-regs.h" 44ebc82efaSNicolas Royer 45ebc82efaSNicolas Royer /* SHA flags */ 46ebc82efaSNicolas Royer #define SHA_FLAGS_BUSY BIT(0) 47ebc82efaSNicolas Royer #define SHA_FLAGS_FINAL BIT(1) 48ebc82efaSNicolas Royer #define SHA_FLAGS_DMA_ACTIVE BIT(2) 49ebc82efaSNicolas Royer #define SHA_FLAGS_OUTPUT_READY BIT(3) 50ebc82efaSNicolas Royer #define SHA_FLAGS_INIT BIT(4) 51ebc82efaSNicolas Royer #define SHA_FLAGS_CPU BIT(5) 52ebc82efaSNicolas Royer #define SHA_FLAGS_DMA_READY BIT(6) 53ebc82efaSNicolas Royer 54ebc82efaSNicolas Royer #define SHA_FLAGS_FINUP BIT(16) 55ebc82efaSNicolas Royer #define SHA_FLAGS_SG BIT(17) 567cee3508SCyrille Pitchen #define SHA_FLAGS_ALGO_MASK GENMASK(22, 18) 57ebc82efaSNicolas Royer #define SHA_FLAGS_SHA1 BIT(18) 58d4905b38SNicolas Royer #define SHA_FLAGS_SHA224 BIT(19) 59d4905b38SNicolas Royer #define SHA_FLAGS_SHA256 BIT(20) 60d4905b38SNicolas Royer #define SHA_FLAGS_SHA384 BIT(21) 61d4905b38SNicolas Royer #define SHA_FLAGS_SHA512 BIT(22) 62d4905b38SNicolas Royer #define SHA_FLAGS_ERROR BIT(23) 63d4905b38SNicolas Royer #define SHA_FLAGS_PAD BIT(24) 647cee3508SCyrille Pitchen #define SHA_FLAGS_RESTORE BIT(25) 65ebc82efaSNicolas Royer 66ebc82efaSNicolas Royer #define SHA_OP_UPDATE 1 67ebc82efaSNicolas Royer #define SHA_OP_FINAL 2 68ebc82efaSNicolas Royer 69cc831d32SCyrille Pitchen #define SHA_BUFFER_LEN (PAGE_SIZE / 16) 70ebc82efaSNicolas Royer 71ebc82efaSNicolas Royer #define ATMEL_SHA_DMA_THRESHOLD 56 72ebc82efaSNicolas Royer 73d4905b38SNicolas Royer struct atmel_sha_caps { 74d4905b38SNicolas Royer bool has_dma; 75d4905b38SNicolas Royer bool has_dualbuff; 76d4905b38SNicolas Royer bool has_sha224; 77d4905b38SNicolas Royer bool has_sha_384_512; 787cee3508SCyrille Pitchen bool has_uihv; 79d4905b38SNicolas Royer }; 80ebc82efaSNicolas Royer 81ebc82efaSNicolas Royer struct atmel_sha_dev; 82ebc82efaSNicolas Royer 83cc831d32SCyrille Pitchen /* 849c4274d9SCyrille Pitchen * .statesize = sizeof(struct atmel_sha_reqctx) must be <= PAGE_SIZE / 8 as 85cc831d32SCyrille Pitchen * tested by the ahash_prepare_alg() function. 86cc831d32SCyrille Pitchen */ 87ebc82efaSNicolas Royer struct atmel_sha_reqctx { 88ebc82efaSNicolas Royer struct atmel_sha_dev *dd; 89ebc82efaSNicolas Royer unsigned long flags; 90ebc82efaSNicolas Royer unsigned long op; 91ebc82efaSNicolas Royer 92d4905b38SNicolas Royer u8 digest[SHA512_DIGEST_SIZE] __aligned(sizeof(u32)); 93d4905b38SNicolas Royer u64 digcnt[2]; 94ebc82efaSNicolas Royer size_t bufcnt; 95ebc82efaSNicolas Royer size_t buflen; 96ebc82efaSNicolas Royer dma_addr_t dma_addr; 97ebc82efaSNicolas Royer 98ebc82efaSNicolas Royer /* walk state */ 99ebc82efaSNicolas Royer struct scatterlist *sg; 100ebc82efaSNicolas Royer unsigned int offset; /* offset in current sg */ 101ebc82efaSNicolas Royer unsigned int total; /* total request */ 102ebc82efaSNicolas Royer 103d4905b38SNicolas Royer size_t block_size; 104d4905b38SNicolas Royer 1059c4274d9SCyrille Pitchen u8 buffer[SHA_BUFFER_LEN + SHA512_BLOCK_SIZE] __aligned(sizeof(u32)); 106ebc82efaSNicolas Royer }; 107ebc82efaSNicolas Royer 108ebc82efaSNicolas Royer struct atmel_sha_ctx { 109ebc82efaSNicolas Royer struct atmel_sha_dev *dd; 110ebc82efaSNicolas Royer 111ebc82efaSNicolas Royer unsigned long flags; 112ebc82efaSNicolas Royer }; 113ebc82efaSNicolas Royer 114d4905b38SNicolas Royer #define ATMEL_SHA_QUEUE_LENGTH 50 115d4905b38SNicolas Royer 116d4905b38SNicolas Royer struct atmel_sha_dma { 117d4905b38SNicolas Royer struct dma_chan *chan; 118d4905b38SNicolas Royer struct dma_slave_config dma_conf; 119d4905b38SNicolas Royer }; 120ebc82efaSNicolas Royer 121ebc82efaSNicolas Royer struct atmel_sha_dev { 122ebc82efaSNicolas Royer struct list_head list; 123ebc82efaSNicolas Royer unsigned long phys_base; 124ebc82efaSNicolas Royer struct device *dev; 125ebc82efaSNicolas Royer struct clk *iclk; 126ebc82efaSNicolas Royer int irq; 127ebc82efaSNicolas Royer void __iomem *io_base; 128ebc82efaSNicolas Royer 129ebc82efaSNicolas Royer spinlock_t lock; 130ebc82efaSNicolas Royer int err; 131ebc82efaSNicolas Royer struct tasklet_struct done_task; 132f56809c3SCyrille Pitchen struct tasklet_struct queue_task; 133ebc82efaSNicolas Royer 134ebc82efaSNicolas Royer unsigned long flags; 135ebc82efaSNicolas Royer struct crypto_queue queue; 136ebc82efaSNicolas Royer struct ahash_request *req; 137d4905b38SNicolas Royer 138d4905b38SNicolas Royer struct atmel_sha_dma dma_lch_in; 139d4905b38SNicolas Royer 140d4905b38SNicolas Royer struct atmel_sha_caps caps; 141d4905b38SNicolas Royer 142d4905b38SNicolas Royer u32 hw_version; 143ebc82efaSNicolas Royer }; 144ebc82efaSNicolas Royer 145ebc82efaSNicolas Royer struct atmel_sha_drv { 146ebc82efaSNicolas Royer struct list_head dev_list; 147ebc82efaSNicolas Royer spinlock_t lock; 148ebc82efaSNicolas Royer }; 149ebc82efaSNicolas Royer 150ebc82efaSNicolas Royer static struct atmel_sha_drv atmel_sha = { 151ebc82efaSNicolas Royer .dev_list = LIST_HEAD_INIT(atmel_sha.dev_list), 152ebc82efaSNicolas Royer .lock = __SPIN_LOCK_UNLOCKED(atmel_sha.lock), 153ebc82efaSNicolas Royer }; 154ebc82efaSNicolas Royer 155ebc82efaSNicolas Royer static inline u32 atmel_sha_read(struct atmel_sha_dev *dd, u32 offset) 156ebc82efaSNicolas Royer { 157ebc82efaSNicolas Royer return readl_relaxed(dd->io_base + offset); 158ebc82efaSNicolas Royer } 159ebc82efaSNicolas Royer 160ebc82efaSNicolas Royer static inline void atmel_sha_write(struct atmel_sha_dev *dd, 161ebc82efaSNicolas Royer u32 offset, u32 value) 162ebc82efaSNicolas Royer { 163ebc82efaSNicolas Royer writel_relaxed(value, dd->io_base + offset); 164ebc82efaSNicolas Royer } 165ebc82efaSNicolas Royer 166ebc82efaSNicolas Royer static size_t atmel_sha_append_sg(struct atmel_sha_reqctx *ctx) 167ebc82efaSNicolas Royer { 168ebc82efaSNicolas Royer size_t count; 169ebc82efaSNicolas Royer 170ebc82efaSNicolas Royer while ((ctx->bufcnt < ctx->buflen) && ctx->total) { 171ebc82efaSNicolas Royer count = min(ctx->sg->length - ctx->offset, ctx->total); 172ebc82efaSNicolas Royer count = min(count, ctx->buflen - ctx->bufcnt); 173ebc82efaSNicolas Royer 174803eeae8SLeilei Zhao if (count <= 0) { 175803eeae8SLeilei Zhao /* 176803eeae8SLeilei Zhao * Check if count <= 0 because the buffer is full or 177803eeae8SLeilei Zhao * because the sg length is 0. In the latest case, 178803eeae8SLeilei Zhao * check if there is another sg in the list, a 0 length 179803eeae8SLeilei Zhao * sg doesn't necessarily mean the end of the sg list. 180803eeae8SLeilei Zhao */ 181803eeae8SLeilei Zhao if ((ctx->sg->length == 0) && !sg_is_last(ctx->sg)) { 182803eeae8SLeilei Zhao ctx->sg = sg_next(ctx->sg); 183803eeae8SLeilei Zhao continue; 184803eeae8SLeilei Zhao } else { 185ebc82efaSNicolas Royer break; 186803eeae8SLeilei Zhao } 187803eeae8SLeilei Zhao } 188ebc82efaSNicolas Royer 189ebc82efaSNicolas Royer scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, ctx->sg, 190ebc82efaSNicolas Royer ctx->offset, count, 0); 191ebc82efaSNicolas Royer 192ebc82efaSNicolas Royer ctx->bufcnt += count; 193ebc82efaSNicolas Royer ctx->offset += count; 194ebc82efaSNicolas Royer ctx->total -= count; 195ebc82efaSNicolas Royer 196ebc82efaSNicolas Royer if (ctx->offset == ctx->sg->length) { 197ebc82efaSNicolas Royer ctx->sg = sg_next(ctx->sg); 198ebc82efaSNicolas Royer if (ctx->sg) 199ebc82efaSNicolas Royer ctx->offset = 0; 200ebc82efaSNicolas Royer else 201ebc82efaSNicolas Royer ctx->total = 0; 202ebc82efaSNicolas Royer } 203ebc82efaSNicolas Royer } 204ebc82efaSNicolas Royer 205ebc82efaSNicolas Royer return 0; 206ebc82efaSNicolas Royer } 207ebc82efaSNicolas Royer 208ebc82efaSNicolas Royer /* 209d4905b38SNicolas Royer * The purpose of this padding is to ensure that the padded message is a 210d4905b38SNicolas Royer * multiple of 512 bits (SHA1/SHA224/SHA256) or 1024 bits (SHA384/SHA512). 211d4905b38SNicolas Royer * The bit "1" is appended at the end of the message followed by 212d4905b38SNicolas Royer * "padlen-1" zero bits. Then a 64 bits block (SHA1/SHA224/SHA256) or 213d4905b38SNicolas Royer * 128 bits block (SHA384/SHA512) equals to the message length in bits 214d4905b38SNicolas Royer * is appended. 215ebc82efaSNicolas Royer * 216d4905b38SNicolas Royer * For SHA1/SHA224/SHA256, padlen is calculated as followed: 217ebc82efaSNicolas Royer * - if message length < 56 bytes then padlen = 56 - message length 218ebc82efaSNicolas Royer * - else padlen = 64 + 56 - message length 219d4905b38SNicolas Royer * 220d4905b38SNicolas Royer * For SHA384/SHA512, padlen is calculated as followed: 221d4905b38SNicolas Royer * - if message length < 112 bytes then padlen = 112 - message length 222d4905b38SNicolas Royer * - else padlen = 128 + 112 - message length 223ebc82efaSNicolas Royer */ 224ebc82efaSNicolas Royer static void atmel_sha_fill_padding(struct atmel_sha_reqctx *ctx, int length) 225ebc82efaSNicolas Royer { 226ebc82efaSNicolas Royer unsigned int index, padlen; 227d4905b38SNicolas Royer u64 bits[2]; 228d4905b38SNicolas Royer u64 size[2]; 229ebc82efaSNicolas Royer 230d4905b38SNicolas Royer size[0] = ctx->digcnt[0]; 231d4905b38SNicolas Royer size[1] = ctx->digcnt[1]; 232ebc82efaSNicolas Royer 233d4905b38SNicolas Royer size[0] += ctx->bufcnt; 234d4905b38SNicolas Royer if (size[0] < ctx->bufcnt) 235d4905b38SNicolas Royer size[1]++; 236d4905b38SNicolas Royer 237d4905b38SNicolas Royer size[0] += length; 238d4905b38SNicolas Royer if (size[0] < length) 239d4905b38SNicolas Royer size[1]++; 240d4905b38SNicolas Royer 241d4905b38SNicolas Royer bits[1] = cpu_to_be64(size[0] << 3); 242d4905b38SNicolas Royer bits[0] = cpu_to_be64(size[1] << 3 | size[0] >> 61); 243d4905b38SNicolas Royer 244d4905b38SNicolas Royer if (ctx->flags & (SHA_FLAGS_SHA384 | SHA_FLAGS_SHA512)) { 245d4905b38SNicolas Royer index = ctx->bufcnt & 0x7f; 246d4905b38SNicolas Royer padlen = (index < 112) ? (112 - index) : ((128+112) - index); 247d4905b38SNicolas Royer *(ctx->buffer + ctx->bufcnt) = 0x80; 248d4905b38SNicolas Royer memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1); 249d4905b38SNicolas Royer memcpy(ctx->buffer + ctx->bufcnt + padlen, bits, 16); 250d4905b38SNicolas Royer ctx->bufcnt += padlen + 16; 251d4905b38SNicolas Royer ctx->flags |= SHA_FLAGS_PAD; 252d4905b38SNicolas Royer } else { 253ebc82efaSNicolas Royer index = ctx->bufcnt & 0x3f; 254ebc82efaSNicolas Royer padlen = (index < 56) ? (56 - index) : ((64+56) - index); 255ebc82efaSNicolas Royer *(ctx->buffer + ctx->bufcnt) = 0x80; 256ebc82efaSNicolas Royer memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1); 257d4905b38SNicolas Royer memcpy(ctx->buffer + ctx->bufcnt + padlen, &bits[1], 8); 258ebc82efaSNicolas Royer ctx->bufcnt += padlen + 8; 259ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_PAD; 260ebc82efaSNicolas Royer } 261d4905b38SNicolas Royer } 262ebc82efaSNicolas Royer 263ebc82efaSNicolas Royer static int atmel_sha_init(struct ahash_request *req) 264ebc82efaSNicolas Royer { 265ebc82efaSNicolas Royer struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 266ebc82efaSNicolas Royer struct atmel_sha_ctx *tctx = crypto_ahash_ctx(tfm); 267ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 268ebc82efaSNicolas Royer struct atmel_sha_dev *dd = NULL; 269ebc82efaSNicolas Royer struct atmel_sha_dev *tmp; 270ebc82efaSNicolas Royer 271ebc82efaSNicolas Royer spin_lock_bh(&atmel_sha.lock); 272ebc82efaSNicolas Royer if (!tctx->dd) { 273ebc82efaSNicolas Royer list_for_each_entry(tmp, &atmel_sha.dev_list, list) { 274ebc82efaSNicolas Royer dd = tmp; 275ebc82efaSNicolas Royer break; 276ebc82efaSNicolas Royer } 277ebc82efaSNicolas Royer tctx->dd = dd; 278ebc82efaSNicolas Royer } else { 279ebc82efaSNicolas Royer dd = tctx->dd; 280ebc82efaSNicolas Royer } 281ebc82efaSNicolas Royer 282ebc82efaSNicolas Royer spin_unlock_bh(&atmel_sha.lock); 283ebc82efaSNicolas Royer 284ebc82efaSNicolas Royer ctx->dd = dd; 285ebc82efaSNicolas Royer 286ebc82efaSNicolas Royer ctx->flags = 0; 287ebc82efaSNicolas Royer 288ebc82efaSNicolas Royer dev_dbg(dd->dev, "init: digest size: %d\n", 289ebc82efaSNicolas Royer crypto_ahash_digestsize(tfm)); 290ebc82efaSNicolas Royer 291d4905b38SNicolas Royer switch (crypto_ahash_digestsize(tfm)) { 292d4905b38SNicolas Royer case SHA1_DIGEST_SIZE: 293ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_SHA1; 294d4905b38SNicolas Royer ctx->block_size = SHA1_BLOCK_SIZE; 295d4905b38SNicolas Royer break; 296d4905b38SNicolas Royer case SHA224_DIGEST_SIZE: 297d4905b38SNicolas Royer ctx->flags |= SHA_FLAGS_SHA224; 298d4905b38SNicolas Royer ctx->block_size = SHA224_BLOCK_SIZE; 299d4905b38SNicolas Royer break; 300d4905b38SNicolas Royer case SHA256_DIGEST_SIZE: 301ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_SHA256; 302d4905b38SNicolas Royer ctx->block_size = SHA256_BLOCK_SIZE; 303d4905b38SNicolas Royer break; 304d4905b38SNicolas Royer case SHA384_DIGEST_SIZE: 305d4905b38SNicolas Royer ctx->flags |= SHA_FLAGS_SHA384; 306d4905b38SNicolas Royer ctx->block_size = SHA384_BLOCK_SIZE; 307d4905b38SNicolas Royer break; 308d4905b38SNicolas Royer case SHA512_DIGEST_SIZE: 309d4905b38SNicolas Royer ctx->flags |= SHA_FLAGS_SHA512; 310d4905b38SNicolas Royer ctx->block_size = SHA512_BLOCK_SIZE; 311d4905b38SNicolas Royer break; 312d4905b38SNicolas Royer default: 313d4905b38SNicolas Royer return -EINVAL; 314d4905b38SNicolas Royer break; 315d4905b38SNicolas Royer } 316ebc82efaSNicolas Royer 317ebc82efaSNicolas Royer ctx->bufcnt = 0; 318d4905b38SNicolas Royer ctx->digcnt[0] = 0; 319d4905b38SNicolas Royer ctx->digcnt[1] = 0; 320ebc82efaSNicolas Royer ctx->buflen = SHA_BUFFER_LEN; 321ebc82efaSNicolas Royer 322ebc82efaSNicolas Royer return 0; 323ebc82efaSNicolas Royer } 324ebc82efaSNicolas Royer 325ebc82efaSNicolas Royer static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma) 326ebc82efaSNicolas Royer { 327ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 3287cee3508SCyrille Pitchen u32 valmr = SHA_MR_MODE_AUTO; 3297cee3508SCyrille Pitchen unsigned int i, hashsize = 0; 330ebc82efaSNicolas Royer 331ebc82efaSNicolas Royer if (likely(dma)) { 332d4905b38SNicolas Royer if (!dd->caps.has_dma) 333ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_IER, SHA_INT_TXBUFE); 334ebc82efaSNicolas Royer valmr = SHA_MR_MODE_PDC; 335d4905b38SNicolas Royer if (dd->caps.has_dualbuff) 336d4905b38SNicolas Royer valmr |= SHA_MR_DUALBUFF; 337ebc82efaSNicolas Royer } else { 338ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY); 339ebc82efaSNicolas Royer } 340ebc82efaSNicolas Royer 3417cee3508SCyrille Pitchen switch (ctx->flags & SHA_FLAGS_ALGO_MASK) { 3427cee3508SCyrille Pitchen case SHA_FLAGS_SHA1: 343d4905b38SNicolas Royer valmr |= SHA_MR_ALGO_SHA1; 3447cee3508SCyrille Pitchen hashsize = SHA1_DIGEST_SIZE; 3457cee3508SCyrille Pitchen break; 3467cee3508SCyrille Pitchen 3477cee3508SCyrille Pitchen case SHA_FLAGS_SHA224: 348d4905b38SNicolas Royer valmr |= SHA_MR_ALGO_SHA224; 3497cee3508SCyrille Pitchen hashsize = SHA256_DIGEST_SIZE; 3507cee3508SCyrille Pitchen break; 3517cee3508SCyrille Pitchen 3527cee3508SCyrille Pitchen case SHA_FLAGS_SHA256: 353ebc82efaSNicolas Royer valmr |= SHA_MR_ALGO_SHA256; 3547cee3508SCyrille Pitchen hashsize = SHA256_DIGEST_SIZE; 3557cee3508SCyrille Pitchen break; 3567cee3508SCyrille Pitchen 3577cee3508SCyrille Pitchen case SHA_FLAGS_SHA384: 358d4905b38SNicolas Royer valmr |= SHA_MR_ALGO_SHA384; 3597cee3508SCyrille Pitchen hashsize = SHA512_DIGEST_SIZE; 3607cee3508SCyrille Pitchen break; 3617cee3508SCyrille Pitchen 3627cee3508SCyrille Pitchen case SHA_FLAGS_SHA512: 363d4905b38SNicolas Royer valmr |= SHA_MR_ALGO_SHA512; 3647cee3508SCyrille Pitchen hashsize = SHA512_DIGEST_SIZE; 3657cee3508SCyrille Pitchen break; 3667cee3508SCyrille Pitchen 3677cee3508SCyrille Pitchen default: 3687cee3508SCyrille Pitchen break; 3697cee3508SCyrille Pitchen } 370ebc82efaSNicolas Royer 371ebc82efaSNicolas Royer /* Setting CR_FIRST only for the first iteration */ 3727cee3508SCyrille Pitchen if (!(ctx->digcnt[0] || ctx->digcnt[1])) { 3737cee3508SCyrille Pitchen atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); 3747cee3508SCyrille Pitchen } else if (dd->caps.has_uihv && (ctx->flags & SHA_FLAGS_RESTORE)) { 3757cee3508SCyrille Pitchen const u32 *hash = (const u32 *)ctx->digest; 376ebc82efaSNicolas Royer 3777cee3508SCyrille Pitchen /* 3787cee3508SCyrille Pitchen * Restore the hardware context: update the User Initialize 3797cee3508SCyrille Pitchen * Hash Value (UIHV) with the value saved when the latest 3807cee3508SCyrille Pitchen * 'update' operation completed on this very same crypto 3817cee3508SCyrille Pitchen * request. 3827cee3508SCyrille Pitchen */ 3837cee3508SCyrille Pitchen ctx->flags &= ~SHA_FLAGS_RESTORE; 3847cee3508SCyrille Pitchen atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV); 3857cee3508SCyrille Pitchen for (i = 0; i < hashsize / sizeof(u32); ++i) 3867cee3508SCyrille Pitchen atmel_sha_write(dd, SHA_REG_DIN(i), hash[i]); 3877cee3508SCyrille Pitchen atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); 3887cee3508SCyrille Pitchen valmr |= SHA_MR_UIHV; 3897cee3508SCyrille Pitchen } 3907cee3508SCyrille Pitchen /* 3917cee3508SCyrille Pitchen * WARNING: If the UIHV feature is not available, the hardware CANNOT 3927cee3508SCyrille Pitchen * process concurrent requests: the internal registers used to store 3937cee3508SCyrille Pitchen * the hash/digest are still set to the partial digest output values 3947cee3508SCyrille Pitchen * computed during the latest round. 3957cee3508SCyrille Pitchen */ 3967cee3508SCyrille Pitchen 397ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_MR, valmr); 398ebc82efaSNicolas Royer } 399ebc82efaSNicolas Royer 400ebc82efaSNicolas Royer static int atmel_sha_xmit_cpu(struct atmel_sha_dev *dd, const u8 *buf, 401ebc82efaSNicolas Royer size_t length, int final) 402ebc82efaSNicolas Royer { 403ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 404ebc82efaSNicolas Royer int count, len32; 405ebc82efaSNicolas Royer const u32 *buffer = (const u32 *)buf; 406ebc82efaSNicolas Royer 407d4905b38SNicolas Royer dev_dbg(dd->dev, "xmit_cpu: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n", 408d4905b38SNicolas Royer ctx->digcnt[1], ctx->digcnt[0], length, final); 409ebc82efaSNicolas Royer 410ebc82efaSNicolas Royer atmel_sha_write_ctrl(dd, 0); 411ebc82efaSNicolas Royer 412ebc82efaSNicolas Royer /* should be non-zero before next lines to disable clocks later */ 413d4905b38SNicolas Royer ctx->digcnt[0] += length; 414d4905b38SNicolas Royer if (ctx->digcnt[0] < length) 415d4905b38SNicolas Royer ctx->digcnt[1]++; 416ebc82efaSNicolas Royer 417ebc82efaSNicolas Royer if (final) 418ebc82efaSNicolas Royer dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */ 419ebc82efaSNicolas Royer 420ebc82efaSNicolas Royer len32 = DIV_ROUND_UP(length, sizeof(u32)); 421ebc82efaSNicolas Royer 422ebc82efaSNicolas Royer dd->flags |= SHA_FLAGS_CPU; 423ebc82efaSNicolas Royer 424ebc82efaSNicolas Royer for (count = 0; count < len32; count++) 425ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_REG_DIN(count), buffer[count]); 426ebc82efaSNicolas Royer 427ebc82efaSNicolas Royer return -EINPROGRESS; 428ebc82efaSNicolas Royer } 429ebc82efaSNicolas Royer 430ebc82efaSNicolas Royer static int atmel_sha_xmit_pdc(struct atmel_sha_dev *dd, dma_addr_t dma_addr1, 431ebc82efaSNicolas Royer size_t length1, dma_addr_t dma_addr2, size_t length2, int final) 432ebc82efaSNicolas Royer { 433ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 434ebc82efaSNicolas Royer int len32; 435ebc82efaSNicolas Royer 436d4905b38SNicolas Royer dev_dbg(dd->dev, "xmit_pdc: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n", 437d4905b38SNicolas Royer ctx->digcnt[1], ctx->digcnt[0], length1, final); 438ebc82efaSNicolas Royer 439ebc82efaSNicolas Royer len32 = DIV_ROUND_UP(length1, sizeof(u32)); 440ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTDIS); 441ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_TPR, dma_addr1); 442ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_TCR, len32); 443ebc82efaSNicolas Royer 444ebc82efaSNicolas Royer len32 = DIV_ROUND_UP(length2, sizeof(u32)); 445ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_TNPR, dma_addr2); 446ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_TNCR, len32); 447ebc82efaSNicolas Royer 448ebc82efaSNicolas Royer atmel_sha_write_ctrl(dd, 1); 449ebc82efaSNicolas Royer 450ebc82efaSNicolas Royer /* should be non-zero before next lines to disable clocks later */ 451d4905b38SNicolas Royer ctx->digcnt[0] += length1; 452d4905b38SNicolas Royer if (ctx->digcnt[0] < length1) 453d4905b38SNicolas Royer ctx->digcnt[1]++; 454ebc82efaSNicolas Royer 455ebc82efaSNicolas Royer if (final) 456ebc82efaSNicolas Royer dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */ 457ebc82efaSNicolas Royer 458ebc82efaSNicolas Royer dd->flags |= SHA_FLAGS_DMA_ACTIVE; 459ebc82efaSNicolas Royer 460ebc82efaSNicolas Royer /* Start DMA transfer */ 461ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTEN); 462ebc82efaSNicolas Royer 463ebc82efaSNicolas Royer return -EINPROGRESS; 464ebc82efaSNicolas Royer } 465ebc82efaSNicolas Royer 466d4905b38SNicolas Royer static void atmel_sha_dma_callback(void *data) 467d4905b38SNicolas Royer { 468d4905b38SNicolas Royer struct atmel_sha_dev *dd = data; 469d4905b38SNicolas Royer 470d4905b38SNicolas Royer /* dma_lch_in - completed - wait DATRDY */ 471d4905b38SNicolas Royer atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY); 472d4905b38SNicolas Royer } 473d4905b38SNicolas Royer 474d4905b38SNicolas Royer static int atmel_sha_xmit_dma(struct atmel_sha_dev *dd, dma_addr_t dma_addr1, 475d4905b38SNicolas Royer size_t length1, dma_addr_t dma_addr2, size_t length2, int final) 476d4905b38SNicolas Royer { 477d4905b38SNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 478d4905b38SNicolas Royer struct dma_async_tx_descriptor *in_desc; 479d4905b38SNicolas Royer struct scatterlist sg[2]; 480d4905b38SNicolas Royer 481d4905b38SNicolas Royer dev_dbg(dd->dev, "xmit_dma: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n", 482d4905b38SNicolas Royer ctx->digcnt[1], ctx->digcnt[0], length1, final); 483d4905b38SNicolas Royer 484d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.src_maxburst = 16; 485d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.dst_maxburst = 16; 486d4905b38SNicolas Royer 487d4905b38SNicolas Royer dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf); 488d4905b38SNicolas Royer 489d4905b38SNicolas Royer if (length2) { 490d4905b38SNicolas Royer sg_init_table(sg, 2); 491d4905b38SNicolas Royer sg_dma_address(&sg[0]) = dma_addr1; 492d4905b38SNicolas Royer sg_dma_len(&sg[0]) = length1; 493d4905b38SNicolas Royer sg_dma_address(&sg[1]) = dma_addr2; 494d4905b38SNicolas Royer sg_dma_len(&sg[1]) = length2; 495d4905b38SNicolas Royer in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, sg, 2, 496d4905b38SNicolas Royer DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 497d4905b38SNicolas Royer } else { 498d4905b38SNicolas Royer sg_init_table(sg, 1); 499d4905b38SNicolas Royer sg_dma_address(&sg[0]) = dma_addr1; 500d4905b38SNicolas Royer sg_dma_len(&sg[0]) = length1; 501d4905b38SNicolas Royer in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, sg, 1, 502d4905b38SNicolas Royer DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 503d4905b38SNicolas Royer } 504d4905b38SNicolas Royer if (!in_desc) 505d4905b38SNicolas Royer return -EINVAL; 506d4905b38SNicolas Royer 507d4905b38SNicolas Royer in_desc->callback = atmel_sha_dma_callback; 508d4905b38SNicolas Royer in_desc->callback_param = dd; 509d4905b38SNicolas Royer 510d4905b38SNicolas Royer atmel_sha_write_ctrl(dd, 1); 511d4905b38SNicolas Royer 512d4905b38SNicolas Royer /* should be non-zero before next lines to disable clocks later */ 513d4905b38SNicolas Royer ctx->digcnt[0] += length1; 514d4905b38SNicolas Royer if (ctx->digcnt[0] < length1) 515d4905b38SNicolas Royer ctx->digcnt[1]++; 516d4905b38SNicolas Royer 517d4905b38SNicolas Royer if (final) 518d4905b38SNicolas Royer dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */ 519d4905b38SNicolas Royer 520d4905b38SNicolas Royer dd->flags |= SHA_FLAGS_DMA_ACTIVE; 521d4905b38SNicolas Royer 522d4905b38SNicolas Royer /* Start DMA transfer */ 523d4905b38SNicolas Royer dmaengine_submit(in_desc); 524d4905b38SNicolas Royer dma_async_issue_pending(dd->dma_lch_in.chan); 525d4905b38SNicolas Royer 526d4905b38SNicolas Royer return -EINPROGRESS; 527d4905b38SNicolas Royer } 528d4905b38SNicolas Royer 529d4905b38SNicolas Royer static int atmel_sha_xmit_start(struct atmel_sha_dev *dd, dma_addr_t dma_addr1, 530d4905b38SNicolas Royer size_t length1, dma_addr_t dma_addr2, size_t length2, int final) 531d4905b38SNicolas Royer { 532d4905b38SNicolas Royer if (dd->caps.has_dma) 533d4905b38SNicolas Royer return atmel_sha_xmit_dma(dd, dma_addr1, length1, 534d4905b38SNicolas Royer dma_addr2, length2, final); 535d4905b38SNicolas Royer else 536d4905b38SNicolas Royer return atmel_sha_xmit_pdc(dd, dma_addr1, length1, 537d4905b38SNicolas Royer dma_addr2, length2, final); 538d4905b38SNicolas Royer } 539d4905b38SNicolas Royer 540ebc82efaSNicolas Royer static int atmel_sha_update_cpu(struct atmel_sha_dev *dd) 541ebc82efaSNicolas Royer { 542ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 543ebc82efaSNicolas Royer int bufcnt; 544ebc82efaSNicolas Royer 545ebc82efaSNicolas Royer atmel_sha_append_sg(ctx); 546ebc82efaSNicolas Royer atmel_sha_fill_padding(ctx, 0); 547ebc82efaSNicolas Royer bufcnt = ctx->bufcnt; 548ebc82efaSNicolas Royer ctx->bufcnt = 0; 549ebc82efaSNicolas Royer 550ebc82efaSNicolas Royer return atmel_sha_xmit_cpu(dd, ctx->buffer, bufcnt, 1); 551ebc82efaSNicolas Royer } 552ebc82efaSNicolas Royer 553ebc82efaSNicolas Royer static int atmel_sha_xmit_dma_map(struct atmel_sha_dev *dd, 554ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx, 555ebc82efaSNicolas Royer size_t length, int final) 556ebc82efaSNicolas Royer { 557ebc82efaSNicolas Royer ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer, 558d4905b38SNicolas Royer ctx->buflen + ctx->block_size, DMA_TO_DEVICE); 559ebc82efaSNicolas Royer if (dma_mapping_error(dd->dev, ctx->dma_addr)) { 560ebc82efaSNicolas Royer dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen + 561d4905b38SNicolas Royer ctx->block_size); 562ebc82efaSNicolas Royer return -EINVAL; 563ebc82efaSNicolas Royer } 564ebc82efaSNicolas Royer 565ebc82efaSNicolas Royer ctx->flags &= ~SHA_FLAGS_SG; 566ebc82efaSNicolas Royer 567ebc82efaSNicolas Royer /* next call does not fail... so no unmap in the case of error */ 568d4905b38SNicolas Royer return atmel_sha_xmit_start(dd, ctx->dma_addr, length, 0, 0, final); 569ebc82efaSNicolas Royer } 570ebc82efaSNicolas Royer 571ebc82efaSNicolas Royer static int atmel_sha_update_dma_slow(struct atmel_sha_dev *dd) 572ebc82efaSNicolas Royer { 573ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 574ebc82efaSNicolas Royer unsigned int final; 575ebc82efaSNicolas Royer size_t count; 576ebc82efaSNicolas Royer 577ebc82efaSNicolas Royer atmel_sha_append_sg(ctx); 578ebc82efaSNicolas Royer 579ebc82efaSNicolas Royer final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total; 580ebc82efaSNicolas Royer 581d4905b38SNicolas Royer dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: 0x%llx 0x%llx, final: %d\n", 582d4905b38SNicolas Royer ctx->bufcnt, ctx->digcnt[1], ctx->digcnt[0], final); 583ebc82efaSNicolas Royer 584ebc82efaSNicolas Royer if (final) 585ebc82efaSNicolas Royer atmel_sha_fill_padding(ctx, 0); 586ebc82efaSNicolas Royer 5870099286bSLudovic Desroches if (final || (ctx->bufcnt == ctx->buflen)) { 588ebc82efaSNicolas Royer count = ctx->bufcnt; 589ebc82efaSNicolas Royer ctx->bufcnt = 0; 590ebc82efaSNicolas Royer return atmel_sha_xmit_dma_map(dd, ctx, count, final); 591ebc82efaSNicolas Royer } 592ebc82efaSNicolas Royer 593ebc82efaSNicolas Royer return 0; 594ebc82efaSNicolas Royer } 595ebc82efaSNicolas Royer 596ebc82efaSNicolas Royer static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd) 597ebc82efaSNicolas Royer { 598ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 599ebc82efaSNicolas Royer unsigned int length, final, tail; 600ebc82efaSNicolas Royer struct scatterlist *sg; 601ebc82efaSNicolas Royer unsigned int count; 602ebc82efaSNicolas Royer 603ebc82efaSNicolas Royer if (!ctx->total) 604ebc82efaSNicolas Royer return 0; 605ebc82efaSNicolas Royer 606ebc82efaSNicolas Royer if (ctx->bufcnt || ctx->offset) 607ebc82efaSNicolas Royer return atmel_sha_update_dma_slow(dd); 608ebc82efaSNicolas Royer 609d4905b38SNicolas Royer dev_dbg(dd->dev, "fast: digcnt: 0x%llx 0x%llx, bufcnt: %u, total: %u\n", 610d4905b38SNicolas Royer ctx->digcnt[1], ctx->digcnt[0], ctx->bufcnt, ctx->total); 611ebc82efaSNicolas Royer 612ebc82efaSNicolas Royer sg = ctx->sg; 613ebc82efaSNicolas Royer 614ebc82efaSNicolas Royer if (!IS_ALIGNED(sg->offset, sizeof(u32))) 615ebc82efaSNicolas Royer return atmel_sha_update_dma_slow(dd); 616ebc82efaSNicolas Royer 617d4905b38SNicolas Royer if (!sg_is_last(sg) && !IS_ALIGNED(sg->length, ctx->block_size)) 618d4905b38SNicolas Royer /* size is not ctx->block_size aligned */ 619ebc82efaSNicolas Royer return atmel_sha_update_dma_slow(dd); 620ebc82efaSNicolas Royer 621ebc82efaSNicolas Royer length = min(ctx->total, sg->length); 622ebc82efaSNicolas Royer 623ebc82efaSNicolas Royer if (sg_is_last(sg)) { 624ebc82efaSNicolas Royer if (!(ctx->flags & SHA_FLAGS_FINUP)) { 625d4905b38SNicolas Royer /* not last sg must be ctx->block_size aligned */ 626d4905b38SNicolas Royer tail = length & (ctx->block_size - 1); 627ebc82efaSNicolas Royer length -= tail; 628ebc82efaSNicolas Royer } 629ebc82efaSNicolas Royer } 630ebc82efaSNicolas Royer 631ebc82efaSNicolas Royer ctx->total -= length; 632ebc82efaSNicolas Royer ctx->offset = length; /* offset where to start slow */ 633ebc82efaSNicolas Royer 634ebc82efaSNicolas Royer final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total; 635ebc82efaSNicolas Royer 636ebc82efaSNicolas Royer /* Add padding */ 637ebc82efaSNicolas Royer if (final) { 638d4905b38SNicolas Royer tail = length & (ctx->block_size - 1); 639ebc82efaSNicolas Royer length -= tail; 640ebc82efaSNicolas Royer ctx->total += tail; 641ebc82efaSNicolas Royer ctx->offset = length; /* offset where to start slow */ 642ebc82efaSNicolas Royer 643ebc82efaSNicolas Royer sg = ctx->sg; 644ebc82efaSNicolas Royer atmel_sha_append_sg(ctx); 645ebc82efaSNicolas Royer 646ebc82efaSNicolas Royer atmel_sha_fill_padding(ctx, length); 647ebc82efaSNicolas Royer 648ebc82efaSNicolas Royer ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer, 649d4905b38SNicolas Royer ctx->buflen + ctx->block_size, DMA_TO_DEVICE); 650ebc82efaSNicolas Royer if (dma_mapping_error(dd->dev, ctx->dma_addr)) { 651ebc82efaSNicolas Royer dev_err(dd->dev, "dma %u bytes error\n", 652d4905b38SNicolas Royer ctx->buflen + ctx->block_size); 653ebc82efaSNicolas Royer return -EINVAL; 654ebc82efaSNicolas Royer } 655ebc82efaSNicolas Royer 656ebc82efaSNicolas Royer if (length == 0) { 657ebc82efaSNicolas Royer ctx->flags &= ~SHA_FLAGS_SG; 658ebc82efaSNicolas Royer count = ctx->bufcnt; 659ebc82efaSNicolas Royer ctx->bufcnt = 0; 660d4905b38SNicolas Royer return atmel_sha_xmit_start(dd, ctx->dma_addr, count, 0, 661ebc82efaSNicolas Royer 0, final); 662ebc82efaSNicolas Royer } else { 663ebc82efaSNicolas Royer ctx->sg = sg; 664ebc82efaSNicolas Royer if (!dma_map_sg(dd->dev, ctx->sg, 1, 665ebc82efaSNicolas Royer DMA_TO_DEVICE)) { 666ebc82efaSNicolas Royer dev_err(dd->dev, "dma_map_sg error\n"); 667ebc82efaSNicolas Royer return -EINVAL; 668ebc82efaSNicolas Royer } 669ebc82efaSNicolas Royer 670ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_SG; 671ebc82efaSNicolas Royer 672ebc82efaSNicolas Royer count = ctx->bufcnt; 673ebc82efaSNicolas Royer ctx->bufcnt = 0; 674d4905b38SNicolas Royer return atmel_sha_xmit_start(dd, sg_dma_address(ctx->sg), 675ebc82efaSNicolas Royer length, ctx->dma_addr, count, final); 676ebc82efaSNicolas Royer } 677ebc82efaSNicolas Royer } 678ebc82efaSNicolas Royer 679ebc82efaSNicolas Royer if (!dma_map_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE)) { 680ebc82efaSNicolas Royer dev_err(dd->dev, "dma_map_sg error\n"); 681ebc82efaSNicolas Royer return -EINVAL; 682ebc82efaSNicolas Royer } 683ebc82efaSNicolas Royer 684ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_SG; 685ebc82efaSNicolas Royer 686ebc82efaSNicolas Royer /* next call does not fail... so no unmap in the case of error */ 687d4905b38SNicolas Royer return atmel_sha_xmit_start(dd, sg_dma_address(ctx->sg), length, 0, 688ebc82efaSNicolas Royer 0, final); 689ebc82efaSNicolas Royer } 690ebc82efaSNicolas Royer 691ebc82efaSNicolas Royer static int atmel_sha_update_dma_stop(struct atmel_sha_dev *dd) 692ebc82efaSNicolas Royer { 693ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 694ebc82efaSNicolas Royer 695ebc82efaSNicolas Royer if (ctx->flags & SHA_FLAGS_SG) { 696ebc82efaSNicolas Royer dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE); 697ebc82efaSNicolas Royer if (ctx->sg->length == ctx->offset) { 698ebc82efaSNicolas Royer ctx->sg = sg_next(ctx->sg); 699ebc82efaSNicolas Royer if (ctx->sg) 700ebc82efaSNicolas Royer ctx->offset = 0; 701ebc82efaSNicolas Royer } 702d4905b38SNicolas Royer if (ctx->flags & SHA_FLAGS_PAD) { 703ebc82efaSNicolas Royer dma_unmap_single(dd->dev, ctx->dma_addr, 704d4905b38SNicolas Royer ctx->buflen + ctx->block_size, DMA_TO_DEVICE); 705d4905b38SNicolas Royer } 706ebc82efaSNicolas Royer } else { 707ebc82efaSNicolas Royer dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen + 708d4905b38SNicolas Royer ctx->block_size, DMA_TO_DEVICE); 709ebc82efaSNicolas Royer } 710ebc82efaSNicolas Royer 711ebc82efaSNicolas Royer return 0; 712ebc82efaSNicolas Royer } 713ebc82efaSNicolas Royer 714ebc82efaSNicolas Royer static int atmel_sha_update_req(struct atmel_sha_dev *dd) 715ebc82efaSNicolas Royer { 716ebc82efaSNicolas Royer struct ahash_request *req = dd->req; 717ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 718ebc82efaSNicolas Royer int err; 719ebc82efaSNicolas Royer 720d4905b38SNicolas Royer dev_dbg(dd->dev, "update_req: total: %u, digcnt: 0x%llx 0x%llx\n", 721d4905b38SNicolas Royer ctx->total, ctx->digcnt[1], ctx->digcnt[0]); 722ebc82efaSNicolas Royer 723ebc82efaSNicolas Royer if (ctx->flags & SHA_FLAGS_CPU) 724ebc82efaSNicolas Royer err = atmel_sha_update_cpu(dd); 725ebc82efaSNicolas Royer else 726ebc82efaSNicolas Royer err = atmel_sha_update_dma_start(dd); 727ebc82efaSNicolas Royer 728ebc82efaSNicolas Royer /* wait for dma completion before can take more data */ 729d4905b38SNicolas Royer dev_dbg(dd->dev, "update: err: %d, digcnt: 0x%llx 0%llx\n", 730d4905b38SNicolas Royer err, ctx->digcnt[1], ctx->digcnt[0]); 731ebc82efaSNicolas Royer 732ebc82efaSNicolas Royer return err; 733ebc82efaSNicolas Royer } 734ebc82efaSNicolas Royer 735ebc82efaSNicolas Royer static int atmel_sha_final_req(struct atmel_sha_dev *dd) 736ebc82efaSNicolas Royer { 737ebc82efaSNicolas Royer struct ahash_request *req = dd->req; 738ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 739ebc82efaSNicolas Royer int err = 0; 740ebc82efaSNicolas Royer int count; 741ebc82efaSNicolas Royer 742ebc82efaSNicolas Royer if (ctx->bufcnt >= ATMEL_SHA_DMA_THRESHOLD) { 743ebc82efaSNicolas Royer atmel_sha_fill_padding(ctx, 0); 744ebc82efaSNicolas Royer count = ctx->bufcnt; 745ebc82efaSNicolas Royer ctx->bufcnt = 0; 746ebc82efaSNicolas Royer err = atmel_sha_xmit_dma_map(dd, ctx, count, 1); 747ebc82efaSNicolas Royer } 748ebc82efaSNicolas Royer /* faster to handle last block with cpu */ 749ebc82efaSNicolas Royer else { 750ebc82efaSNicolas Royer atmel_sha_fill_padding(ctx, 0); 751ebc82efaSNicolas Royer count = ctx->bufcnt; 752ebc82efaSNicolas Royer ctx->bufcnt = 0; 753ebc82efaSNicolas Royer err = atmel_sha_xmit_cpu(dd, ctx->buffer, count, 1); 754ebc82efaSNicolas Royer } 755ebc82efaSNicolas Royer 756ebc82efaSNicolas Royer dev_dbg(dd->dev, "final_req: err: %d\n", err); 757ebc82efaSNicolas Royer 758ebc82efaSNicolas Royer return err; 759ebc82efaSNicolas Royer } 760ebc82efaSNicolas Royer 761ebc82efaSNicolas Royer static void atmel_sha_copy_hash(struct ahash_request *req) 762ebc82efaSNicolas Royer { 763ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 764ebc82efaSNicolas Royer u32 *hash = (u32 *)ctx->digest; 7657cee3508SCyrille Pitchen unsigned int i, hashsize; 766ebc82efaSNicolas Royer 7677cee3508SCyrille Pitchen switch (ctx->flags & SHA_FLAGS_ALGO_MASK) { 7687cee3508SCyrille Pitchen case SHA_FLAGS_SHA1: 7697cee3508SCyrille Pitchen hashsize = SHA1_DIGEST_SIZE; 7707cee3508SCyrille Pitchen break; 7717cee3508SCyrille Pitchen 7727cee3508SCyrille Pitchen case SHA_FLAGS_SHA224: 7737cee3508SCyrille Pitchen case SHA_FLAGS_SHA256: 7747cee3508SCyrille Pitchen hashsize = SHA256_DIGEST_SIZE; 7757cee3508SCyrille Pitchen break; 7767cee3508SCyrille Pitchen 7777cee3508SCyrille Pitchen case SHA_FLAGS_SHA384: 7787cee3508SCyrille Pitchen case SHA_FLAGS_SHA512: 7797cee3508SCyrille Pitchen hashsize = SHA512_DIGEST_SIZE; 7807cee3508SCyrille Pitchen break; 7817cee3508SCyrille Pitchen 7827cee3508SCyrille Pitchen default: 7837cee3508SCyrille Pitchen /* Should not happen... */ 7847cee3508SCyrille Pitchen return; 7857cee3508SCyrille Pitchen } 7867cee3508SCyrille Pitchen 7877cee3508SCyrille Pitchen for (i = 0; i < hashsize / sizeof(u32); ++i) 788ebc82efaSNicolas Royer hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i)); 7897cee3508SCyrille Pitchen ctx->flags |= SHA_FLAGS_RESTORE; 790ebc82efaSNicolas Royer } 791ebc82efaSNicolas Royer 792ebc82efaSNicolas Royer static void atmel_sha_copy_ready_hash(struct ahash_request *req) 793ebc82efaSNicolas Royer { 794ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 795ebc82efaSNicolas Royer 796ebc82efaSNicolas Royer if (!req->result) 797ebc82efaSNicolas Royer return; 798ebc82efaSNicolas Royer 799d4905b38SNicolas Royer if (ctx->flags & SHA_FLAGS_SHA1) 800ebc82efaSNicolas Royer memcpy(req->result, ctx->digest, SHA1_DIGEST_SIZE); 801d4905b38SNicolas Royer else if (ctx->flags & SHA_FLAGS_SHA224) 802d4905b38SNicolas Royer memcpy(req->result, ctx->digest, SHA224_DIGEST_SIZE); 803d4905b38SNicolas Royer else if (ctx->flags & SHA_FLAGS_SHA256) 804ebc82efaSNicolas Royer memcpy(req->result, ctx->digest, SHA256_DIGEST_SIZE); 805d4905b38SNicolas Royer else if (ctx->flags & SHA_FLAGS_SHA384) 806d4905b38SNicolas Royer memcpy(req->result, ctx->digest, SHA384_DIGEST_SIZE); 807d4905b38SNicolas Royer else 808d4905b38SNicolas Royer memcpy(req->result, ctx->digest, SHA512_DIGEST_SIZE); 809ebc82efaSNicolas Royer } 810ebc82efaSNicolas Royer 811ebc82efaSNicolas Royer static int atmel_sha_finish(struct ahash_request *req) 812ebc82efaSNicolas Royer { 813ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 814ebc82efaSNicolas Royer struct atmel_sha_dev *dd = ctx->dd; 815ebc82efaSNicolas Royer 816d4905b38SNicolas Royer if (ctx->digcnt[0] || ctx->digcnt[1]) 817ebc82efaSNicolas Royer atmel_sha_copy_ready_hash(req); 818ebc82efaSNicolas Royer 819d4905b38SNicolas Royer dev_dbg(dd->dev, "digcnt: 0x%llx 0x%llx, bufcnt: %d\n", ctx->digcnt[1], 820d4905b38SNicolas Royer ctx->digcnt[0], ctx->bufcnt); 821ebc82efaSNicolas Royer 822871b88a8SRahul Pathak return 0; 823ebc82efaSNicolas Royer } 824ebc82efaSNicolas Royer 825ebc82efaSNicolas Royer static void atmel_sha_finish_req(struct ahash_request *req, int err) 826ebc82efaSNicolas Royer { 827ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 828ebc82efaSNicolas Royer struct atmel_sha_dev *dd = ctx->dd; 829ebc82efaSNicolas Royer 830ebc82efaSNicolas Royer if (!err) { 831ebc82efaSNicolas Royer atmel_sha_copy_hash(req); 832ebc82efaSNicolas Royer if (SHA_FLAGS_FINAL & dd->flags) 833ebc82efaSNicolas Royer err = atmel_sha_finish(req); 834ebc82efaSNicolas Royer } else { 835ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_ERROR; 836ebc82efaSNicolas Royer } 837ebc82efaSNicolas Royer 838ebc82efaSNicolas Royer /* atomic operation is not needed here */ 839ebc82efaSNicolas Royer dd->flags &= ~(SHA_FLAGS_BUSY | SHA_FLAGS_FINAL | SHA_FLAGS_CPU | 840ebc82efaSNicolas Royer SHA_FLAGS_DMA_READY | SHA_FLAGS_OUTPUT_READY); 841ebc82efaSNicolas Royer 842ebc82efaSNicolas Royer clk_disable_unprepare(dd->iclk); 843ebc82efaSNicolas Royer 844ebc82efaSNicolas Royer if (req->base.complete) 845ebc82efaSNicolas Royer req->base.complete(&req->base, err); 846ebc82efaSNicolas Royer 847ebc82efaSNicolas Royer /* handle new request */ 848f56809c3SCyrille Pitchen tasklet_schedule(&dd->queue_task); 849ebc82efaSNicolas Royer } 850ebc82efaSNicolas Royer 851ebc82efaSNicolas Royer static int atmel_sha_hw_init(struct atmel_sha_dev *dd) 852ebc82efaSNicolas Royer { 8539d83d299SLABBE Corentin int err; 8549d83d299SLABBE Corentin 8559d83d299SLABBE Corentin err = clk_prepare_enable(dd->iclk); 8569d83d299SLABBE Corentin if (err) 8579d83d299SLABBE Corentin return err; 858ebc82efaSNicolas Royer 859d4905b38SNicolas Royer if (!(SHA_FLAGS_INIT & dd->flags)) { 860ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_CR, SHA_CR_SWRST); 861ebc82efaSNicolas Royer dd->flags |= SHA_FLAGS_INIT; 862ebc82efaSNicolas Royer dd->err = 0; 863ebc82efaSNicolas Royer } 864ebc82efaSNicolas Royer 865ebc82efaSNicolas Royer return 0; 866ebc82efaSNicolas Royer } 867ebc82efaSNicolas Royer 868d4905b38SNicolas Royer static inline unsigned int atmel_sha_get_version(struct atmel_sha_dev *dd) 869d4905b38SNicolas Royer { 870d4905b38SNicolas Royer return atmel_sha_read(dd, SHA_HW_VERSION) & 0x00000fff; 871d4905b38SNicolas Royer } 872d4905b38SNicolas Royer 873d4905b38SNicolas Royer static void atmel_sha_hw_version_init(struct atmel_sha_dev *dd) 874d4905b38SNicolas Royer { 875d4905b38SNicolas Royer atmel_sha_hw_init(dd); 876d4905b38SNicolas Royer 877d4905b38SNicolas Royer dd->hw_version = atmel_sha_get_version(dd); 878d4905b38SNicolas Royer 879d4905b38SNicolas Royer dev_info(dd->dev, 880d4905b38SNicolas Royer "version: 0x%x\n", dd->hw_version); 881d4905b38SNicolas Royer 882d4905b38SNicolas Royer clk_disable_unprepare(dd->iclk); 883d4905b38SNicolas Royer } 884d4905b38SNicolas Royer 885ebc82efaSNicolas Royer static int atmel_sha_handle_queue(struct atmel_sha_dev *dd, 886ebc82efaSNicolas Royer struct ahash_request *req) 887ebc82efaSNicolas Royer { 888ebc82efaSNicolas Royer struct crypto_async_request *async_req, *backlog; 889ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx; 890ebc82efaSNicolas Royer unsigned long flags; 891ebc82efaSNicolas Royer int err = 0, ret = 0; 892ebc82efaSNicolas Royer 893ebc82efaSNicolas Royer spin_lock_irqsave(&dd->lock, flags); 894ebc82efaSNicolas Royer if (req) 895ebc82efaSNicolas Royer ret = ahash_enqueue_request(&dd->queue, req); 896ebc82efaSNicolas Royer 897ebc82efaSNicolas Royer if (SHA_FLAGS_BUSY & dd->flags) { 898ebc82efaSNicolas Royer spin_unlock_irqrestore(&dd->lock, flags); 899ebc82efaSNicolas Royer return ret; 900ebc82efaSNicolas Royer } 901ebc82efaSNicolas Royer 902ebc82efaSNicolas Royer backlog = crypto_get_backlog(&dd->queue); 903ebc82efaSNicolas Royer async_req = crypto_dequeue_request(&dd->queue); 904ebc82efaSNicolas Royer if (async_req) 905ebc82efaSNicolas Royer dd->flags |= SHA_FLAGS_BUSY; 906ebc82efaSNicolas Royer 907ebc82efaSNicolas Royer spin_unlock_irqrestore(&dd->lock, flags); 908ebc82efaSNicolas Royer 909ebc82efaSNicolas Royer if (!async_req) 910ebc82efaSNicolas Royer return ret; 911ebc82efaSNicolas Royer 912ebc82efaSNicolas Royer if (backlog) 913ebc82efaSNicolas Royer backlog->complete(backlog, -EINPROGRESS); 914ebc82efaSNicolas Royer 915ebc82efaSNicolas Royer req = ahash_request_cast(async_req); 916ebc82efaSNicolas Royer dd->req = req; 917ebc82efaSNicolas Royer ctx = ahash_request_ctx(req); 918ebc82efaSNicolas Royer 919ebc82efaSNicolas Royer dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n", 920ebc82efaSNicolas Royer ctx->op, req->nbytes); 921ebc82efaSNicolas Royer 922ebc82efaSNicolas Royer err = atmel_sha_hw_init(dd); 923ebc82efaSNicolas Royer 924ebc82efaSNicolas Royer if (err) 925ebc82efaSNicolas Royer goto err1; 926ebc82efaSNicolas Royer 927ebc82efaSNicolas Royer if (ctx->op == SHA_OP_UPDATE) { 928ebc82efaSNicolas Royer err = atmel_sha_update_req(dd); 929d4905b38SNicolas Royer if (err != -EINPROGRESS && (ctx->flags & SHA_FLAGS_FINUP)) 930ebc82efaSNicolas Royer /* no final() after finup() */ 931ebc82efaSNicolas Royer err = atmel_sha_final_req(dd); 932ebc82efaSNicolas Royer } else if (ctx->op == SHA_OP_FINAL) { 933ebc82efaSNicolas Royer err = atmel_sha_final_req(dd); 934ebc82efaSNicolas Royer } 935ebc82efaSNicolas Royer 936ebc82efaSNicolas Royer err1: 937ebc82efaSNicolas Royer if (err != -EINPROGRESS) 938ebc82efaSNicolas Royer /* done_task will not finish it, so do it here */ 939ebc82efaSNicolas Royer atmel_sha_finish_req(req, err); 940ebc82efaSNicolas Royer 941ebc82efaSNicolas Royer dev_dbg(dd->dev, "exit, err: %d\n", err); 942ebc82efaSNicolas Royer 943ebc82efaSNicolas Royer return ret; 944ebc82efaSNicolas Royer } 945ebc82efaSNicolas Royer 946ebc82efaSNicolas Royer static int atmel_sha_enqueue(struct ahash_request *req, unsigned int op) 947ebc82efaSNicolas Royer { 948ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 949ebc82efaSNicolas Royer struct atmel_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm); 950ebc82efaSNicolas Royer struct atmel_sha_dev *dd = tctx->dd; 951ebc82efaSNicolas Royer 952ebc82efaSNicolas Royer ctx->op = op; 953ebc82efaSNicolas Royer 954ebc82efaSNicolas Royer return atmel_sha_handle_queue(dd, req); 955ebc82efaSNicolas Royer } 956ebc82efaSNicolas Royer 957ebc82efaSNicolas Royer static int atmel_sha_update(struct ahash_request *req) 958ebc82efaSNicolas Royer { 959ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 960ebc82efaSNicolas Royer 961ebc82efaSNicolas Royer if (!req->nbytes) 962ebc82efaSNicolas Royer return 0; 963ebc82efaSNicolas Royer 964ebc82efaSNicolas Royer ctx->total = req->nbytes; 965ebc82efaSNicolas Royer ctx->sg = req->src; 966ebc82efaSNicolas Royer ctx->offset = 0; 967ebc82efaSNicolas Royer 968ebc82efaSNicolas Royer if (ctx->flags & SHA_FLAGS_FINUP) { 969ebc82efaSNicolas Royer if (ctx->bufcnt + ctx->total < ATMEL_SHA_DMA_THRESHOLD) 970ebc82efaSNicolas Royer /* faster to use CPU for short transfers */ 971ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_CPU; 972ebc82efaSNicolas Royer } else if (ctx->bufcnt + ctx->total < ctx->buflen) { 973ebc82efaSNicolas Royer atmel_sha_append_sg(ctx); 974ebc82efaSNicolas Royer return 0; 975ebc82efaSNicolas Royer } 976ebc82efaSNicolas Royer return atmel_sha_enqueue(req, SHA_OP_UPDATE); 977ebc82efaSNicolas Royer } 978ebc82efaSNicolas Royer 979ebc82efaSNicolas Royer static int atmel_sha_final(struct ahash_request *req) 980ebc82efaSNicolas Royer { 981ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 982ebc82efaSNicolas Royer 983ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_FINUP; 984ebc82efaSNicolas Royer 985ebc82efaSNicolas Royer if (ctx->flags & SHA_FLAGS_ERROR) 986ebc82efaSNicolas Royer return 0; /* uncompleted hash is not needed */ 987ebc82efaSNicolas Royer 988ad84112aSCyrille Pitchen if (ctx->flags & SHA_FLAGS_PAD) 989ebc82efaSNicolas Royer /* copy ready hash (+ finalize hmac) */ 990ebc82efaSNicolas Royer return atmel_sha_finish(req); 991ebc82efaSNicolas Royer 992ad84112aSCyrille Pitchen return atmel_sha_enqueue(req, SHA_OP_FINAL); 993ebc82efaSNicolas Royer } 994ebc82efaSNicolas Royer 995ebc82efaSNicolas Royer static int atmel_sha_finup(struct ahash_request *req) 996ebc82efaSNicolas Royer { 997ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 998ebc82efaSNicolas Royer int err1, err2; 999ebc82efaSNicolas Royer 1000ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_FINUP; 1001ebc82efaSNicolas Royer 1002ebc82efaSNicolas Royer err1 = atmel_sha_update(req); 1003ebc82efaSNicolas Royer if (err1 == -EINPROGRESS || err1 == -EBUSY) 1004ebc82efaSNicolas Royer return err1; 1005ebc82efaSNicolas Royer 1006ebc82efaSNicolas Royer /* 1007ebc82efaSNicolas Royer * final() has to be always called to cleanup resources 1008ebc82efaSNicolas Royer * even if udpate() failed, except EINPROGRESS 1009ebc82efaSNicolas Royer */ 1010ebc82efaSNicolas Royer err2 = atmel_sha_final(req); 1011ebc82efaSNicolas Royer 1012ebc82efaSNicolas Royer return err1 ?: err2; 1013ebc82efaSNicolas Royer } 1014ebc82efaSNicolas Royer 1015ebc82efaSNicolas Royer static int atmel_sha_digest(struct ahash_request *req) 1016ebc82efaSNicolas Royer { 1017ebc82efaSNicolas Royer return atmel_sha_init(req) ?: atmel_sha_finup(req); 1018ebc82efaSNicolas Royer } 1019ebc82efaSNicolas Royer 1020cc831d32SCyrille Pitchen 1021cc831d32SCyrille Pitchen static int atmel_sha_export(struct ahash_request *req, void *out) 1022cc831d32SCyrille Pitchen { 1023cc831d32SCyrille Pitchen const struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 1024cc831d32SCyrille Pitchen 10259c4274d9SCyrille Pitchen memcpy(out, ctx, sizeof(*ctx)); 1026cc831d32SCyrille Pitchen return 0; 1027cc831d32SCyrille Pitchen } 1028cc831d32SCyrille Pitchen 1029cc831d32SCyrille Pitchen static int atmel_sha_import(struct ahash_request *req, const void *in) 1030cc831d32SCyrille Pitchen { 1031cc831d32SCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 1032cc831d32SCyrille Pitchen 10339c4274d9SCyrille Pitchen memcpy(ctx, in, sizeof(*ctx)); 1034cc831d32SCyrille Pitchen return 0; 1035cc831d32SCyrille Pitchen } 1036cc831d32SCyrille Pitchen 1037be95f0faSSvenning Sørensen static int atmel_sha_cra_init(struct crypto_tfm *tfm) 1038ebc82efaSNicolas Royer { 1039ebc82efaSNicolas Royer crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), 10409c4274d9SCyrille Pitchen sizeof(struct atmel_sha_reqctx)); 1041ebc82efaSNicolas Royer 1042ebc82efaSNicolas Royer return 0; 1043ebc82efaSNicolas Royer } 1044ebc82efaSNicolas Royer 1045d4905b38SNicolas Royer static struct ahash_alg sha_1_256_algs[] = { 1046ebc82efaSNicolas Royer { 1047ebc82efaSNicolas Royer .init = atmel_sha_init, 1048ebc82efaSNicolas Royer .update = atmel_sha_update, 1049ebc82efaSNicolas Royer .final = atmel_sha_final, 1050ebc82efaSNicolas Royer .finup = atmel_sha_finup, 1051ebc82efaSNicolas Royer .digest = atmel_sha_digest, 1052cc831d32SCyrille Pitchen .export = atmel_sha_export, 1053cc831d32SCyrille Pitchen .import = atmel_sha_import, 1054ebc82efaSNicolas Royer .halg = { 1055ebc82efaSNicolas Royer .digestsize = SHA1_DIGEST_SIZE, 10569c4274d9SCyrille Pitchen .statesize = sizeof(struct atmel_sha_reqctx), 1057ebc82efaSNicolas Royer .base = { 1058ebc82efaSNicolas Royer .cra_name = "sha1", 1059ebc82efaSNicolas Royer .cra_driver_name = "atmel-sha1", 1060ebc82efaSNicolas Royer .cra_priority = 100, 1061be95f0faSSvenning Sørensen .cra_flags = CRYPTO_ALG_ASYNC, 1062ebc82efaSNicolas Royer .cra_blocksize = SHA1_BLOCK_SIZE, 1063ebc82efaSNicolas Royer .cra_ctxsize = sizeof(struct atmel_sha_ctx), 1064ebc82efaSNicolas Royer .cra_alignmask = 0, 1065ebc82efaSNicolas Royer .cra_module = THIS_MODULE, 1066ebc82efaSNicolas Royer .cra_init = atmel_sha_cra_init, 1067ebc82efaSNicolas Royer } 1068ebc82efaSNicolas Royer } 1069ebc82efaSNicolas Royer }, 1070ebc82efaSNicolas Royer { 1071ebc82efaSNicolas Royer .init = atmel_sha_init, 1072ebc82efaSNicolas Royer .update = atmel_sha_update, 1073ebc82efaSNicolas Royer .final = atmel_sha_final, 1074ebc82efaSNicolas Royer .finup = atmel_sha_finup, 1075ebc82efaSNicolas Royer .digest = atmel_sha_digest, 1076cc831d32SCyrille Pitchen .export = atmel_sha_export, 1077cc831d32SCyrille Pitchen .import = atmel_sha_import, 1078ebc82efaSNicolas Royer .halg = { 1079ebc82efaSNicolas Royer .digestsize = SHA256_DIGEST_SIZE, 10809c4274d9SCyrille Pitchen .statesize = sizeof(struct atmel_sha_reqctx), 1081ebc82efaSNicolas Royer .base = { 1082ebc82efaSNicolas Royer .cra_name = "sha256", 1083ebc82efaSNicolas Royer .cra_driver_name = "atmel-sha256", 1084ebc82efaSNicolas Royer .cra_priority = 100, 1085be95f0faSSvenning Sørensen .cra_flags = CRYPTO_ALG_ASYNC, 1086ebc82efaSNicolas Royer .cra_blocksize = SHA256_BLOCK_SIZE, 1087ebc82efaSNicolas Royer .cra_ctxsize = sizeof(struct atmel_sha_ctx), 1088ebc82efaSNicolas Royer .cra_alignmask = 0, 1089ebc82efaSNicolas Royer .cra_module = THIS_MODULE, 1090ebc82efaSNicolas Royer .cra_init = atmel_sha_cra_init, 1091ebc82efaSNicolas Royer } 1092ebc82efaSNicolas Royer } 1093ebc82efaSNicolas Royer }, 1094ebc82efaSNicolas Royer }; 1095ebc82efaSNicolas Royer 1096d4905b38SNicolas Royer static struct ahash_alg sha_224_alg = { 1097d4905b38SNicolas Royer .init = atmel_sha_init, 1098d4905b38SNicolas Royer .update = atmel_sha_update, 1099d4905b38SNicolas Royer .final = atmel_sha_final, 1100d4905b38SNicolas Royer .finup = atmel_sha_finup, 1101d4905b38SNicolas Royer .digest = atmel_sha_digest, 1102cc831d32SCyrille Pitchen .export = atmel_sha_export, 1103cc831d32SCyrille Pitchen .import = atmel_sha_import, 1104d4905b38SNicolas Royer .halg = { 1105d4905b38SNicolas Royer .digestsize = SHA224_DIGEST_SIZE, 11069c4274d9SCyrille Pitchen .statesize = sizeof(struct atmel_sha_reqctx), 1107d4905b38SNicolas Royer .base = { 1108d4905b38SNicolas Royer .cra_name = "sha224", 1109d4905b38SNicolas Royer .cra_driver_name = "atmel-sha224", 1110d4905b38SNicolas Royer .cra_priority = 100, 1111be95f0faSSvenning Sørensen .cra_flags = CRYPTO_ALG_ASYNC, 1112d4905b38SNicolas Royer .cra_blocksize = SHA224_BLOCK_SIZE, 1113d4905b38SNicolas Royer .cra_ctxsize = sizeof(struct atmel_sha_ctx), 1114d4905b38SNicolas Royer .cra_alignmask = 0, 1115d4905b38SNicolas Royer .cra_module = THIS_MODULE, 1116d4905b38SNicolas Royer .cra_init = atmel_sha_cra_init, 1117d4905b38SNicolas Royer } 1118d4905b38SNicolas Royer } 1119d4905b38SNicolas Royer }; 1120d4905b38SNicolas Royer 1121d4905b38SNicolas Royer static struct ahash_alg sha_384_512_algs[] = { 1122d4905b38SNicolas Royer { 1123d4905b38SNicolas Royer .init = atmel_sha_init, 1124d4905b38SNicolas Royer .update = atmel_sha_update, 1125d4905b38SNicolas Royer .final = atmel_sha_final, 1126d4905b38SNicolas Royer .finup = atmel_sha_finup, 1127d4905b38SNicolas Royer .digest = atmel_sha_digest, 1128cc831d32SCyrille Pitchen .export = atmel_sha_export, 1129cc831d32SCyrille Pitchen .import = atmel_sha_import, 1130d4905b38SNicolas Royer .halg = { 1131d4905b38SNicolas Royer .digestsize = SHA384_DIGEST_SIZE, 11329c4274d9SCyrille Pitchen .statesize = sizeof(struct atmel_sha_reqctx), 1133d4905b38SNicolas Royer .base = { 1134d4905b38SNicolas Royer .cra_name = "sha384", 1135d4905b38SNicolas Royer .cra_driver_name = "atmel-sha384", 1136d4905b38SNicolas Royer .cra_priority = 100, 1137be95f0faSSvenning Sørensen .cra_flags = CRYPTO_ALG_ASYNC, 1138d4905b38SNicolas Royer .cra_blocksize = SHA384_BLOCK_SIZE, 1139d4905b38SNicolas Royer .cra_ctxsize = sizeof(struct atmel_sha_ctx), 1140d4905b38SNicolas Royer .cra_alignmask = 0x3, 1141d4905b38SNicolas Royer .cra_module = THIS_MODULE, 1142d4905b38SNicolas Royer .cra_init = atmel_sha_cra_init, 1143d4905b38SNicolas Royer } 1144d4905b38SNicolas Royer } 1145d4905b38SNicolas Royer }, 1146d4905b38SNicolas Royer { 1147d4905b38SNicolas Royer .init = atmel_sha_init, 1148d4905b38SNicolas Royer .update = atmel_sha_update, 1149d4905b38SNicolas Royer .final = atmel_sha_final, 1150d4905b38SNicolas Royer .finup = atmel_sha_finup, 1151d4905b38SNicolas Royer .digest = atmel_sha_digest, 1152cc831d32SCyrille Pitchen .export = atmel_sha_export, 1153cc831d32SCyrille Pitchen .import = atmel_sha_import, 1154d4905b38SNicolas Royer .halg = { 1155d4905b38SNicolas Royer .digestsize = SHA512_DIGEST_SIZE, 11569c4274d9SCyrille Pitchen .statesize = sizeof(struct atmel_sha_reqctx), 1157d4905b38SNicolas Royer .base = { 1158d4905b38SNicolas Royer .cra_name = "sha512", 1159d4905b38SNicolas Royer .cra_driver_name = "atmel-sha512", 1160d4905b38SNicolas Royer .cra_priority = 100, 1161be95f0faSSvenning Sørensen .cra_flags = CRYPTO_ALG_ASYNC, 1162d4905b38SNicolas Royer .cra_blocksize = SHA512_BLOCK_SIZE, 1163d4905b38SNicolas Royer .cra_ctxsize = sizeof(struct atmel_sha_ctx), 1164d4905b38SNicolas Royer .cra_alignmask = 0x3, 1165d4905b38SNicolas Royer .cra_module = THIS_MODULE, 1166d4905b38SNicolas Royer .cra_init = atmel_sha_cra_init, 1167d4905b38SNicolas Royer } 1168d4905b38SNicolas Royer } 1169d4905b38SNicolas Royer }, 1170d4905b38SNicolas Royer }; 1171d4905b38SNicolas Royer 1172f56809c3SCyrille Pitchen static void atmel_sha_queue_task(unsigned long data) 1173f56809c3SCyrille Pitchen { 1174f56809c3SCyrille Pitchen struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data; 1175f56809c3SCyrille Pitchen 1176f56809c3SCyrille Pitchen atmel_sha_handle_queue(dd, NULL); 1177f56809c3SCyrille Pitchen } 1178f56809c3SCyrille Pitchen 1179ebc82efaSNicolas Royer static void atmel_sha_done_task(unsigned long data) 1180ebc82efaSNicolas Royer { 1181ebc82efaSNicolas Royer struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data; 1182ebc82efaSNicolas Royer int err = 0; 1183ebc82efaSNicolas Royer 1184ebc82efaSNicolas Royer if (SHA_FLAGS_CPU & dd->flags) { 1185ebc82efaSNicolas Royer if (SHA_FLAGS_OUTPUT_READY & dd->flags) { 1186ebc82efaSNicolas Royer dd->flags &= ~SHA_FLAGS_OUTPUT_READY; 1187ebc82efaSNicolas Royer goto finish; 1188ebc82efaSNicolas Royer } 1189ebc82efaSNicolas Royer } else if (SHA_FLAGS_DMA_READY & dd->flags) { 1190ebc82efaSNicolas Royer if (SHA_FLAGS_DMA_ACTIVE & dd->flags) { 1191ebc82efaSNicolas Royer dd->flags &= ~SHA_FLAGS_DMA_ACTIVE; 1192ebc82efaSNicolas Royer atmel_sha_update_dma_stop(dd); 1193ebc82efaSNicolas Royer if (dd->err) { 1194ebc82efaSNicolas Royer err = dd->err; 1195ebc82efaSNicolas Royer goto finish; 1196ebc82efaSNicolas Royer } 1197ebc82efaSNicolas Royer } 1198ebc82efaSNicolas Royer if (SHA_FLAGS_OUTPUT_READY & dd->flags) { 1199ebc82efaSNicolas Royer /* hash or semi-hash ready */ 1200ebc82efaSNicolas Royer dd->flags &= ~(SHA_FLAGS_DMA_READY | 1201ebc82efaSNicolas Royer SHA_FLAGS_OUTPUT_READY); 1202ebc82efaSNicolas Royer err = atmel_sha_update_dma_start(dd); 1203ebc82efaSNicolas Royer if (err != -EINPROGRESS) 1204ebc82efaSNicolas Royer goto finish; 1205ebc82efaSNicolas Royer } 1206ebc82efaSNicolas Royer } 1207ebc82efaSNicolas Royer return; 1208ebc82efaSNicolas Royer 1209ebc82efaSNicolas Royer finish: 1210ebc82efaSNicolas Royer /* finish curent request */ 1211ebc82efaSNicolas Royer atmel_sha_finish_req(dd->req, err); 1212ebc82efaSNicolas Royer } 1213ebc82efaSNicolas Royer 1214ebc82efaSNicolas Royer static irqreturn_t atmel_sha_irq(int irq, void *dev_id) 1215ebc82efaSNicolas Royer { 1216ebc82efaSNicolas Royer struct atmel_sha_dev *sha_dd = dev_id; 1217ebc82efaSNicolas Royer u32 reg; 1218ebc82efaSNicolas Royer 1219ebc82efaSNicolas Royer reg = atmel_sha_read(sha_dd, SHA_ISR); 1220ebc82efaSNicolas Royer if (reg & atmel_sha_read(sha_dd, SHA_IMR)) { 1221ebc82efaSNicolas Royer atmel_sha_write(sha_dd, SHA_IDR, reg); 1222ebc82efaSNicolas Royer if (SHA_FLAGS_BUSY & sha_dd->flags) { 1223ebc82efaSNicolas Royer sha_dd->flags |= SHA_FLAGS_OUTPUT_READY; 1224ebc82efaSNicolas Royer if (!(SHA_FLAGS_CPU & sha_dd->flags)) 1225ebc82efaSNicolas Royer sha_dd->flags |= SHA_FLAGS_DMA_READY; 1226ebc82efaSNicolas Royer tasklet_schedule(&sha_dd->done_task); 1227ebc82efaSNicolas Royer } else { 1228ebc82efaSNicolas Royer dev_warn(sha_dd->dev, "SHA interrupt when no active requests.\n"); 1229ebc82efaSNicolas Royer } 1230ebc82efaSNicolas Royer return IRQ_HANDLED; 1231ebc82efaSNicolas Royer } 1232ebc82efaSNicolas Royer 1233ebc82efaSNicolas Royer return IRQ_NONE; 1234ebc82efaSNicolas Royer } 1235ebc82efaSNicolas Royer 1236ebc82efaSNicolas Royer static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd) 1237ebc82efaSNicolas Royer { 1238ebc82efaSNicolas Royer int i; 1239ebc82efaSNicolas Royer 1240d4905b38SNicolas Royer for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) 1241d4905b38SNicolas Royer crypto_unregister_ahash(&sha_1_256_algs[i]); 1242d4905b38SNicolas Royer 1243d4905b38SNicolas Royer if (dd->caps.has_sha224) 1244d4905b38SNicolas Royer crypto_unregister_ahash(&sha_224_alg); 1245d4905b38SNicolas Royer 1246d4905b38SNicolas Royer if (dd->caps.has_sha_384_512) { 1247d4905b38SNicolas Royer for (i = 0; i < ARRAY_SIZE(sha_384_512_algs); i++) 1248d4905b38SNicolas Royer crypto_unregister_ahash(&sha_384_512_algs[i]); 1249d4905b38SNicolas Royer } 1250ebc82efaSNicolas Royer } 1251ebc82efaSNicolas Royer 1252ebc82efaSNicolas Royer static int atmel_sha_register_algs(struct atmel_sha_dev *dd) 1253ebc82efaSNicolas Royer { 1254ebc82efaSNicolas Royer int err, i, j; 1255ebc82efaSNicolas Royer 1256d4905b38SNicolas Royer for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) { 1257d4905b38SNicolas Royer err = crypto_register_ahash(&sha_1_256_algs[i]); 1258ebc82efaSNicolas Royer if (err) 1259d4905b38SNicolas Royer goto err_sha_1_256_algs; 1260d4905b38SNicolas Royer } 1261d4905b38SNicolas Royer 1262d4905b38SNicolas Royer if (dd->caps.has_sha224) { 1263d4905b38SNicolas Royer err = crypto_register_ahash(&sha_224_alg); 1264d4905b38SNicolas Royer if (err) 1265d4905b38SNicolas Royer goto err_sha_224_algs; 1266d4905b38SNicolas Royer } 1267d4905b38SNicolas Royer 1268d4905b38SNicolas Royer if (dd->caps.has_sha_384_512) { 1269d4905b38SNicolas Royer for (i = 0; i < ARRAY_SIZE(sha_384_512_algs); i++) { 1270d4905b38SNicolas Royer err = crypto_register_ahash(&sha_384_512_algs[i]); 1271d4905b38SNicolas Royer if (err) 1272d4905b38SNicolas Royer goto err_sha_384_512_algs; 1273d4905b38SNicolas Royer } 1274ebc82efaSNicolas Royer } 1275ebc82efaSNicolas Royer 1276ebc82efaSNicolas Royer return 0; 1277ebc82efaSNicolas Royer 1278d4905b38SNicolas Royer err_sha_384_512_algs: 1279ebc82efaSNicolas Royer for (j = 0; j < i; j++) 1280d4905b38SNicolas Royer crypto_unregister_ahash(&sha_384_512_algs[j]); 1281d4905b38SNicolas Royer crypto_unregister_ahash(&sha_224_alg); 1282d4905b38SNicolas Royer err_sha_224_algs: 1283d4905b38SNicolas Royer i = ARRAY_SIZE(sha_1_256_algs); 1284d4905b38SNicolas Royer err_sha_1_256_algs: 1285d4905b38SNicolas Royer for (j = 0; j < i; j++) 1286d4905b38SNicolas Royer crypto_unregister_ahash(&sha_1_256_algs[j]); 1287ebc82efaSNicolas Royer 1288ebc82efaSNicolas Royer return err; 1289ebc82efaSNicolas Royer } 1290ebc82efaSNicolas Royer 1291d4905b38SNicolas Royer static bool atmel_sha_filter(struct dma_chan *chan, void *slave) 1292d4905b38SNicolas Royer { 1293d4905b38SNicolas Royer struct at_dma_slave *sl = slave; 1294d4905b38SNicolas Royer 1295d4905b38SNicolas Royer if (sl && sl->dma_dev == chan->device->dev) { 1296d4905b38SNicolas Royer chan->private = sl; 1297d4905b38SNicolas Royer return true; 1298d4905b38SNicolas Royer } else { 1299d4905b38SNicolas Royer return false; 1300d4905b38SNicolas Royer } 1301d4905b38SNicolas Royer } 1302d4905b38SNicolas Royer 1303d4905b38SNicolas Royer static int atmel_sha_dma_init(struct atmel_sha_dev *dd, 1304d4905b38SNicolas Royer struct crypto_platform_data *pdata) 1305d4905b38SNicolas Royer { 1306d4905b38SNicolas Royer int err = -ENOMEM; 1307d4905b38SNicolas Royer dma_cap_mask_t mask_in; 1308d4905b38SNicolas Royer 1309d4905b38SNicolas Royer /* Try to grab DMA channel */ 1310d4905b38SNicolas Royer dma_cap_zero(mask_in); 1311d4905b38SNicolas Royer dma_cap_set(DMA_SLAVE, mask_in); 1312d4905b38SNicolas Royer 1313abfe7ae4SNicolas Ferre dd->dma_lch_in.chan = dma_request_slave_channel_compat(mask_in, 1314abfe7ae4SNicolas Ferre atmel_sha_filter, &pdata->dma_slave->rxdata, dd->dev, "tx"); 1315abfe7ae4SNicolas Ferre if (!dd->dma_lch_in.chan) { 1316abfe7ae4SNicolas Ferre dev_warn(dd->dev, "no DMA channel available\n"); 1317d4905b38SNicolas Royer return err; 1318abfe7ae4SNicolas Ferre } 1319d4905b38SNicolas Royer 1320d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV; 1321d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base + 1322d4905b38SNicolas Royer SHA_REG_DIN(0); 1323d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.src_maxburst = 1; 1324d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.src_addr_width = 1325d4905b38SNicolas Royer DMA_SLAVE_BUSWIDTH_4_BYTES; 1326d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.dst_maxburst = 1; 1327d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.dst_addr_width = 1328d4905b38SNicolas Royer DMA_SLAVE_BUSWIDTH_4_BYTES; 1329d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.device_fc = false; 1330d4905b38SNicolas Royer 1331d4905b38SNicolas Royer return 0; 1332d4905b38SNicolas Royer } 1333d4905b38SNicolas Royer 1334d4905b38SNicolas Royer static void atmel_sha_dma_cleanup(struct atmel_sha_dev *dd) 1335d4905b38SNicolas Royer { 1336d4905b38SNicolas Royer dma_release_channel(dd->dma_lch_in.chan); 1337d4905b38SNicolas Royer } 1338d4905b38SNicolas Royer 1339d4905b38SNicolas Royer static void atmel_sha_get_cap(struct atmel_sha_dev *dd) 1340d4905b38SNicolas Royer { 1341d4905b38SNicolas Royer 1342d4905b38SNicolas Royer dd->caps.has_dma = 0; 1343d4905b38SNicolas Royer dd->caps.has_dualbuff = 0; 1344d4905b38SNicolas Royer dd->caps.has_sha224 = 0; 1345d4905b38SNicolas Royer dd->caps.has_sha_384_512 = 0; 13467cee3508SCyrille Pitchen dd->caps.has_uihv = 0; 1347d4905b38SNicolas Royer 1348d4905b38SNicolas Royer /* keep only major version number */ 1349d4905b38SNicolas Royer switch (dd->hw_version & 0xff0) { 1350507c5cc2SCyrille Pitchen case 0x510: 1351507c5cc2SCyrille Pitchen dd->caps.has_dma = 1; 1352507c5cc2SCyrille Pitchen dd->caps.has_dualbuff = 1; 1353507c5cc2SCyrille Pitchen dd->caps.has_sha224 = 1; 1354507c5cc2SCyrille Pitchen dd->caps.has_sha_384_512 = 1; 13557cee3508SCyrille Pitchen dd->caps.has_uihv = 1; 1356507c5cc2SCyrille Pitchen break; 1357141824d0SLeilei Zhao case 0x420: 1358141824d0SLeilei Zhao dd->caps.has_dma = 1; 1359141824d0SLeilei Zhao dd->caps.has_dualbuff = 1; 1360141824d0SLeilei Zhao dd->caps.has_sha224 = 1; 1361141824d0SLeilei Zhao dd->caps.has_sha_384_512 = 1; 13627cee3508SCyrille Pitchen dd->caps.has_uihv = 1; 1363141824d0SLeilei Zhao break; 1364d4905b38SNicolas Royer case 0x410: 1365d4905b38SNicolas Royer dd->caps.has_dma = 1; 1366d4905b38SNicolas Royer dd->caps.has_dualbuff = 1; 1367d4905b38SNicolas Royer dd->caps.has_sha224 = 1; 1368d4905b38SNicolas Royer dd->caps.has_sha_384_512 = 1; 1369d4905b38SNicolas Royer break; 1370d4905b38SNicolas Royer case 0x400: 1371d4905b38SNicolas Royer dd->caps.has_dma = 1; 1372d4905b38SNicolas Royer dd->caps.has_dualbuff = 1; 1373d4905b38SNicolas Royer dd->caps.has_sha224 = 1; 1374d4905b38SNicolas Royer break; 1375d4905b38SNicolas Royer case 0x320: 1376d4905b38SNicolas Royer break; 1377d4905b38SNicolas Royer default: 1378d4905b38SNicolas Royer dev_warn(dd->dev, 1379d4905b38SNicolas Royer "Unmanaged sha version, set minimum capabilities\n"); 1380d4905b38SNicolas Royer break; 1381d4905b38SNicolas Royer } 1382d4905b38SNicolas Royer } 1383d4905b38SNicolas Royer 1384abfe7ae4SNicolas Ferre #if defined(CONFIG_OF) 1385abfe7ae4SNicolas Ferre static const struct of_device_id atmel_sha_dt_ids[] = { 1386abfe7ae4SNicolas Ferre { .compatible = "atmel,at91sam9g46-sha" }, 1387abfe7ae4SNicolas Ferre { /* sentinel */ } 1388abfe7ae4SNicolas Ferre }; 1389abfe7ae4SNicolas Ferre 1390abfe7ae4SNicolas Ferre MODULE_DEVICE_TABLE(of, atmel_sha_dt_ids); 1391abfe7ae4SNicolas Ferre 1392abfe7ae4SNicolas Ferre static struct crypto_platform_data *atmel_sha_of_init(struct platform_device *pdev) 1393abfe7ae4SNicolas Ferre { 1394abfe7ae4SNicolas Ferre struct device_node *np = pdev->dev.of_node; 1395abfe7ae4SNicolas Ferre struct crypto_platform_data *pdata; 1396abfe7ae4SNicolas Ferre 1397abfe7ae4SNicolas Ferre if (!np) { 1398abfe7ae4SNicolas Ferre dev_err(&pdev->dev, "device node not found\n"); 1399abfe7ae4SNicolas Ferre return ERR_PTR(-EINVAL); 1400abfe7ae4SNicolas Ferre } 1401abfe7ae4SNicolas Ferre 1402abfe7ae4SNicolas Ferre pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 1403abfe7ae4SNicolas Ferre if (!pdata) { 1404abfe7ae4SNicolas Ferre dev_err(&pdev->dev, "could not allocate memory for pdata\n"); 1405abfe7ae4SNicolas Ferre return ERR_PTR(-ENOMEM); 1406abfe7ae4SNicolas Ferre } 1407abfe7ae4SNicolas Ferre 1408abfe7ae4SNicolas Ferre pdata->dma_slave = devm_kzalloc(&pdev->dev, 1409abfe7ae4SNicolas Ferre sizeof(*(pdata->dma_slave)), 1410abfe7ae4SNicolas Ferre GFP_KERNEL); 1411abfe7ae4SNicolas Ferre if (!pdata->dma_slave) { 1412abfe7ae4SNicolas Ferre dev_err(&pdev->dev, "could not allocate memory for dma_slave\n"); 1413abfe7ae4SNicolas Ferre return ERR_PTR(-ENOMEM); 1414abfe7ae4SNicolas Ferre } 1415abfe7ae4SNicolas Ferre 1416abfe7ae4SNicolas Ferre return pdata; 1417abfe7ae4SNicolas Ferre } 1418abfe7ae4SNicolas Ferre #else /* CONFIG_OF */ 1419abfe7ae4SNicolas Ferre static inline struct crypto_platform_data *atmel_sha_of_init(struct platform_device *dev) 1420abfe7ae4SNicolas Ferre { 1421abfe7ae4SNicolas Ferre return ERR_PTR(-EINVAL); 1422abfe7ae4SNicolas Ferre } 1423abfe7ae4SNicolas Ferre #endif 1424abfe7ae4SNicolas Ferre 142549cfe4dbSGreg Kroah-Hartman static int atmel_sha_probe(struct platform_device *pdev) 1426ebc82efaSNicolas Royer { 1427ebc82efaSNicolas Royer struct atmel_sha_dev *sha_dd; 1428d4905b38SNicolas Royer struct crypto_platform_data *pdata; 1429ebc82efaSNicolas Royer struct device *dev = &pdev->dev; 1430ebc82efaSNicolas Royer struct resource *sha_res; 1431ebc82efaSNicolas Royer int err; 1432ebc82efaSNicolas Royer 1433b0e8b341SLABBE Corentin sha_dd = devm_kzalloc(&pdev->dev, sizeof(*sha_dd), GFP_KERNEL); 1434ebc82efaSNicolas Royer if (sha_dd == NULL) { 1435ebc82efaSNicolas Royer dev_err(dev, "unable to alloc data struct.\n"); 1436ebc82efaSNicolas Royer err = -ENOMEM; 1437ebc82efaSNicolas Royer goto sha_dd_err; 1438ebc82efaSNicolas Royer } 1439ebc82efaSNicolas Royer 1440ebc82efaSNicolas Royer sha_dd->dev = dev; 1441ebc82efaSNicolas Royer 1442ebc82efaSNicolas Royer platform_set_drvdata(pdev, sha_dd); 1443ebc82efaSNicolas Royer 1444ebc82efaSNicolas Royer INIT_LIST_HEAD(&sha_dd->list); 144562728e82SLeilei Zhao spin_lock_init(&sha_dd->lock); 1446ebc82efaSNicolas Royer 1447ebc82efaSNicolas Royer tasklet_init(&sha_dd->done_task, atmel_sha_done_task, 1448ebc82efaSNicolas Royer (unsigned long)sha_dd); 1449f56809c3SCyrille Pitchen tasklet_init(&sha_dd->queue_task, atmel_sha_queue_task, 1450f56809c3SCyrille Pitchen (unsigned long)sha_dd); 1451ebc82efaSNicolas Royer 1452ebc82efaSNicolas Royer crypto_init_queue(&sha_dd->queue, ATMEL_SHA_QUEUE_LENGTH); 1453ebc82efaSNicolas Royer 1454ebc82efaSNicolas Royer sha_dd->irq = -1; 1455ebc82efaSNicolas Royer 1456ebc82efaSNicolas Royer /* Get the base address */ 1457ebc82efaSNicolas Royer sha_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1458ebc82efaSNicolas Royer if (!sha_res) { 1459ebc82efaSNicolas Royer dev_err(dev, "no MEM resource info\n"); 1460ebc82efaSNicolas Royer err = -ENODEV; 1461ebc82efaSNicolas Royer goto res_err; 1462ebc82efaSNicolas Royer } 1463ebc82efaSNicolas Royer sha_dd->phys_base = sha_res->start; 1464ebc82efaSNicolas Royer 1465ebc82efaSNicolas Royer /* Get the IRQ */ 1466ebc82efaSNicolas Royer sha_dd->irq = platform_get_irq(pdev, 0); 1467ebc82efaSNicolas Royer if (sha_dd->irq < 0) { 1468ebc82efaSNicolas Royer dev_err(dev, "no IRQ resource info\n"); 1469ebc82efaSNicolas Royer err = sha_dd->irq; 1470ebc82efaSNicolas Royer goto res_err; 1471ebc82efaSNicolas Royer } 1472ebc82efaSNicolas Royer 1473b0e8b341SLABBE Corentin err = devm_request_irq(&pdev->dev, sha_dd->irq, atmel_sha_irq, 1474b0e8b341SLABBE Corentin IRQF_SHARED, "atmel-sha", sha_dd); 1475ebc82efaSNicolas Royer if (err) { 1476ebc82efaSNicolas Royer dev_err(dev, "unable to request sha irq.\n"); 1477ebc82efaSNicolas Royer goto res_err; 1478ebc82efaSNicolas Royer } 1479ebc82efaSNicolas Royer 1480ebc82efaSNicolas Royer /* Initializing the clock */ 1481b0e8b341SLABBE Corentin sha_dd->iclk = devm_clk_get(&pdev->dev, "sha_clk"); 1482ebc82efaSNicolas Royer if (IS_ERR(sha_dd->iclk)) { 1483be208356SColin Ian King dev_err(dev, "clock initialization failed.\n"); 1484ebc82efaSNicolas Royer err = PTR_ERR(sha_dd->iclk); 1485b0e8b341SLABBE Corentin goto res_err; 1486ebc82efaSNicolas Royer } 1487ebc82efaSNicolas Royer 1488b0e8b341SLABBE Corentin sha_dd->io_base = devm_ioremap_resource(&pdev->dev, sha_res); 14899b52d55fSVladimir Zapolskiy if (IS_ERR(sha_dd->io_base)) { 1490ebc82efaSNicolas Royer dev_err(dev, "can't ioremap\n"); 14919b52d55fSVladimir Zapolskiy err = PTR_ERR(sha_dd->io_base); 1492b0e8b341SLABBE Corentin goto res_err; 1493ebc82efaSNicolas Royer } 1494ebc82efaSNicolas Royer 1495d4905b38SNicolas Royer atmel_sha_hw_version_init(sha_dd); 1496d4905b38SNicolas Royer 1497d4905b38SNicolas Royer atmel_sha_get_cap(sha_dd); 1498d4905b38SNicolas Royer 1499d4905b38SNicolas Royer if (sha_dd->caps.has_dma) { 1500d4905b38SNicolas Royer pdata = pdev->dev.platform_data; 1501d4905b38SNicolas Royer if (!pdata) { 1502abfe7ae4SNicolas Ferre pdata = atmel_sha_of_init(pdev); 1503abfe7ae4SNicolas Ferre if (IS_ERR(pdata)) { 1504d4905b38SNicolas Royer dev_err(&pdev->dev, "platform data not available\n"); 1505abfe7ae4SNicolas Ferre err = PTR_ERR(pdata); 1506b0e8b341SLABBE Corentin goto res_err; 1507abfe7ae4SNicolas Ferre } 1508abfe7ae4SNicolas Ferre } 1509abfe7ae4SNicolas Ferre if (!pdata->dma_slave) { 1510d4905b38SNicolas Royer err = -ENXIO; 1511b0e8b341SLABBE Corentin goto res_err; 1512d4905b38SNicolas Royer } 1513d4905b38SNicolas Royer err = atmel_sha_dma_init(sha_dd, pdata); 1514d4905b38SNicolas Royer if (err) 1515d4905b38SNicolas Royer goto err_sha_dma; 1516abfe7ae4SNicolas Ferre 1517abfe7ae4SNicolas Ferre dev_info(dev, "using %s for DMA transfers\n", 1518abfe7ae4SNicolas Ferre dma_chan_name(sha_dd->dma_lch_in.chan)); 1519d4905b38SNicolas Royer } 1520d4905b38SNicolas Royer 1521ebc82efaSNicolas Royer spin_lock(&atmel_sha.lock); 1522ebc82efaSNicolas Royer list_add_tail(&sha_dd->list, &atmel_sha.dev_list); 1523ebc82efaSNicolas Royer spin_unlock(&atmel_sha.lock); 1524ebc82efaSNicolas Royer 1525ebc82efaSNicolas Royer err = atmel_sha_register_algs(sha_dd); 1526ebc82efaSNicolas Royer if (err) 1527ebc82efaSNicolas Royer goto err_algs; 1528ebc82efaSNicolas Royer 15291ca5b7d9SNicolas Ferre dev_info(dev, "Atmel SHA1/SHA256%s%s\n", 15301ca5b7d9SNicolas Ferre sha_dd->caps.has_sha224 ? "/SHA224" : "", 15311ca5b7d9SNicolas Ferre sha_dd->caps.has_sha_384_512 ? "/SHA384/SHA512" : ""); 1532ebc82efaSNicolas Royer 1533ebc82efaSNicolas Royer return 0; 1534ebc82efaSNicolas Royer 1535ebc82efaSNicolas Royer err_algs: 1536ebc82efaSNicolas Royer spin_lock(&atmel_sha.lock); 1537ebc82efaSNicolas Royer list_del(&sha_dd->list); 1538ebc82efaSNicolas Royer spin_unlock(&atmel_sha.lock); 1539d4905b38SNicolas Royer if (sha_dd->caps.has_dma) 1540d4905b38SNicolas Royer atmel_sha_dma_cleanup(sha_dd); 1541d4905b38SNicolas Royer err_sha_dma: 1542ebc82efaSNicolas Royer res_err: 1543f56809c3SCyrille Pitchen tasklet_kill(&sha_dd->queue_task); 1544ebc82efaSNicolas Royer tasklet_kill(&sha_dd->done_task); 1545ebc82efaSNicolas Royer sha_dd_err: 1546ebc82efaSNicolas Royer dev_err(dev, "initialization failed.\n"); 1547ebc82efaSNicolas Royer 1548ebc82efaSNicolas Royer return err; 1549ebc82efaSNicolas Royer } 1550ebc82efaSNicolas Royer 155149cfe4dbSGreg Kroah-Hartman static int atmel_sha_remove(struct platform_device *pdev) 1552ebc82efaSNicolas Royer { 1553ebc82efaSNicolas Royer static struct atmel_sha_dev *sha_dd; 1554ebc82efaSNicolas Royer 1555ebc82efaSNicolas Royer sha_dd = platform_get_drvdata(pdev); 1556ebc82efaSNicolas Royer if (!sha_dd) 1557ebc82efaSNicolas Royer return -ENODEV; 1558ebc82efaSNicolas Royer spin_lock(&atmel_sha.lock); 1559ebc82efaSNicolas Royer list_del(&sha_dd->list); 1560ebc82efaSNicolas Royer spin_unlock(&atmel_sha.lock); 1561ebc82efaSNicolas Royer 1562ebc82efaSNicolas Royer atmel_sha_unregister_algs(sha_dd); 1563ebc82efaSNicolas Royer 1564f56809c3SCyrille Pitchen tasklet_kill(&sha_dd->queue_task); 1565ebc82efaSNicolas Royer tasklet_kill(&sha_dd->done_task); 1566ebc82efaSNicolas Royer 1567d4905b38SNicolas Royer if (sha_dd->caps.has_dma) 1568d4905b38SNicolas Royer atmel_sha_dma_cleanup(sha_dd); 1569d4905b38SNicolas Royer 1570ebc82efaSNicolas Royer iounmap(sha_dd->io_base); 1571ebc82efaSNicolas Royer 1572ebc82efaSNicolas Royer clk_put(sha_dd->iclk); 1573ebc82efaSNicolas Royer 1574ebc82efaSNicolas Royer if (sha_dd->irq >= 0) 1575ebc82efaSNicolas Royer free_irq(sha_dd->irq, sha_dd); 1576ebc82efaSNicolas Royer 1577ebc82efaSNicolas Royer return 0; 1578ebc82efaSNicolas Royer } 1579ebc82efaSNicolas Royer 1580ebc82efaSNicolas Royer static struct platform_driver atmel_sha_driver = { 1581ebc82efaSNicolas Royer .probe = atmel_sha_probe, 158249cfe4dbSGreg Kroah-Hartman .remove = atmel_sha_remove, 1583ebc82efaSNicolas Royer .driver = { 1584ebc82efaSNicolas Royer .name = "atmel_sha", 1585abfe7ae4SNicolas Ferre .of_match_table = of_match_ptr(atmel_sha_dt_ids), 1586ebc82efaSNicolas Royer }, 1587ebc82efaSNicolas Royer }; 1588ebc82efaSNicolas Royer 1589ebc82efaSNicolas Royer module_platform_driver(atmel_sha_driver); 1590ebc82efaSNicolas Royer 1591d4905b38SNicolas Royer MODULE_DESCRIPTION("Atmel SHA (1/256/224/384/512) hw acceleration support."); 1592ebc82efaSNicolas Royer MODULE_LICENSE("GPL v2"); 1593ebc82efaSNicolas Royer MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique"); 1594