static void rk_ahash_reg_init(struct rk_crypto_info *dev) { int reg_status = 0; reg_status = CRYPTO_READ(dev, RK_CRYPTO_CTRL) | RK_CRYPTO_HASH_FLUSH | _SBF(0xffff, 16); CRYPTO_WRITE(dev, RK_CRYPTO_CTRL, reg_status); reg_status = CRYPTO_READ(dev, RK_CRYPTO_CTRL); reg_status &= (~RK_CRYPTO_HASH_FLUSH); reg_status |= _SBF(0xffff, 16); CRYPTO_WRITE(dev, RK_CRYPTO_CTRL, reg_status); memset_io(dev->reg + RK_CRYPTO_HASH_DOUT_0, 0, 32); CRYPTO_WRITE(dev, RK_CRYPTO_INTENA, RK_CRYPTO_HRDMA_ERR_ENA | RK_CRYPTO_HRDMA_DONE_ENA); CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, RK_CRYPTO_HRDMA_ERR_INT | RK_CRYPTO_HRDMA_DONE_INT); CRYPTO_WRITE(dev, RK_CRYPTO_HASH_CTRL, dev->mode | RK_CRYPTO_HASH_SWAP_DO); CRYPTO_WRITE(dev, RK_CRYPTO_CONF, RK_CRYPTO_BYTESWAP_HRFIFO | RK_CRYPTO_BYTESWAP_BRFIFO | RK_CRYPTO_BYTESWAP_BTFIFO); CRYPTO_WRITE(dev, RK_CRYPTO_HASH_MSG_LEN, dev->total); }
static irqreturn_t rk_crypto_irq_handle(int irq, void *dev_id) { struct rk_crypto_info *dev = platform_get_drvdata(dev_id); u32 interrupt_status; spin_lock(&dev->lock); interrupt_status = CRYPTO_READ(dev, RK_CRYPTO_INTSTS); CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, interrupt_status); if (interrupt_status & 0x0a) { dev_warn(dev->dev, "DMA Error\n"); dev->err = -EFAULT; } tasklet_schedule(&dev->done_task); spin_unlock(&dev->lock); return IRQ_HANDLED; }
static irqreturn_t rk_crypto_irq_handle(int irq, void *dev_id) { struct rk_crypto_info *dev = platform_get_drvdata(dev_id); u32 interrupt_status; int err = 0; spin_lock(&dev->lock); interrupt_status = CRYPTO_READ(dev, RK_CRYPTO_INTSTS); CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, interrupt_status); if (interrupt_status & 0x0a) { dev_warn(dev->dev, "DMA Error\n"); err = -EFAULT; } else if (interrupt_status & 0x05) { err = dev->update(dev); } if (err) dev->complete(dev, err); spin_unlock(&dev->lock); return IRQ_HANDLED; }
static int rk_ahash_digest(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct rk_ahash_ctx *tctx = crypto_tfm_ctx(req->base.tfm); struct rk_crypto_info *dev = NULL; unsigned long flags; int ret; if (!req->nbytes) return zero_message_process(req); dev = tctx->dev; dev->total = req->nbytes; dev->left_bytes = req->nbytes; dev->aligned = 0; dev->mode = 0; dev->align_size = 4; dev->sg_dst = NULL; dev->sg_src = req->src; dev->first = req->src; dev->nents = sg_nents(req->src); switch (crypto_ahash_digestsize(tfm)) { case SHA1_DIGEST_SIZE: dev->mode = RK_CRYPTO_HASH_SHA1; break; case SHA256_DIGEST_SIZE: dev->mode = RK_CRYPTO_HASH_SHA256; break; case MD5_DIGEST_SIZE: dev->mode = RK_CRYPTO_HASH_MD5; break; default: return -EINVAL; } rk_ahash_reg_init(dev); spin_lock_irqsave(&dev->lock, flags); ret = crypto_enqueue_request(&dev->queue, &req->base); spin_unlock_irqrestore(&dev->lock, flags); tasklet_schedule(&dev->crypto_tasklet); /* * it will take some time to process date after last dma transmission. * * waiting time is relative with the last date len, * so cannot set a fixed time here. * 10-50 makes system not call here frequently wasting * efficiency, and make it response quickly when dma * complete. */ while (!CRYPTO_READ(dev, RK_CRYPTO_HASH_STS)) usleep_range(10, 50); memcpy_fromio(req->result, dev->reg + RK_CRYPTO_HASH_DOUT_0, crypto_ahash_digestsize(tfm)); return 0; }