/*
* This file is part of STM32 Crypto driver for Linux.
*
* Copyright (C) 2017, STMicroelectronics - All Rights Reserved
* Author(s): Lionel DEBIEVE <lionel.debieve@st.com> for STMicroelectronics.
*
* License terms: GPL V2.0.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <linux/clk.h>
#include <linux/crypto.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <crypto/engine.h>
#include <crypto/hash.h>
#include <crypto/md5.h>
#include <crypto/scatterwalk.h>
#include <crypto/sha.h>
#include <crypto/internal/hash.h>
#define HASH_CR 0x00
#define HASH_DIN 0x04
#define HASH_STR 0x08
#define HASH_IMR 0x20
#define HASH_SR 0x24
#define HASH_CSR(x) (0x0F8 + ((x) * 0x04))
#define HASH_HREG(x) (0x310 + ((x) * 0x04))
#define HASH_HWCFGR 0x3F0
#define HASH_VER 0x3F4
#define HASH_ID 0x3F8
/* Control Register */
#define HASH_CR_INIT BIT(2)
#define HASH_CR_DMAE BIT(3)
#define HASH_CR_DATATYPE_POS 4
#define HASH_CR_MODE BIT(6)
#define HASH_CR_MDMAT BIT(13)
#define HASH_CR_DMAA BIT(14)
#define HASH_CR_LKEY BIT(16)
#define HASH_CR_ALGO_SHA1 0x0
#define HASH_CR_ALGO_MD5 0x80
#define HASH_CR_ALGO_SHA224 0x40000
#define HASH_CR_ALGO_SHA256 0x40080
/* Interrupt */
#define HASH_DINIE BIT(0)
#define HASH_DCIE BIT(1)
/* Interrupt Mask */
#define HASH_MASK_CALC_COMPLETION BIT(0)
#define HASH_MASK_DATA_INPUT BIT(1)
/* Context swap register */
#define HASH_CSR_REGISTER_NUMBER 53
/* Status Flags */
#define HASH_SR_DATA_INPUT_READY BIT(0)
#define HASH_SR_OUTPUT_READY BIT(1)
#define HASH_SR_DMA_ACTIVE BIT(2)
#define HASH_SR_BUSY BIT(3)
/* STR Register */
#define HASH_STR_NBLW_MASK GENMASK(4, 0)
#define HASH_STR_DCAL BIT(8)
#define HASH_FLAGS_INIT BIT(0)
#define HASH_FLAGS_OUTPUT_READY BIT(1)
#define HASH_FLAGS_CPU BIT(2)
#define HASH_FLAGS_DMA_READY BIT(3)
#define HASH_FLAGS_DMA_ACTIVE BIT(4)
#define HASH_FLAGS_HMAC_INIT BIT(5)
#define HASH_FLAGS_HMAC_FINAL BIT(6)
#define HASH_FLAGS_HMAC_KEY BIT(7)
#define HASH_FLAGS_FINAL BIT(15)
#define HASH_FLAGS_FINUP BIT(16)
#define HASH_FLAGS_ALGO_MASK GENMASK(21, 18)
#define HASH_FLAGS_MD5 BIT(18)
#define HASH_FLAGS_SHA1 BIT(19)
#define HASH_FLAGS_SHA224 BIT(20)
#define HASH_FLAGS_SHA256 BIT(21)
#define HASH_FLAGS_ERRORS BIT(22)
#define HASH_FLAGS_HMAC BIT(23)
#define HASH_OP_UPDATE 1
#define HASH_OP_FINAL 2
enum stm32_hash_data_format {
HASH_DATA_32_BITS = 0x0,
HASH_DATA_16_BITS = 0x1,
HASH_DATA_8_BITS = 0x2,
HASH_DATA_1_BIT = 0x3
};
#define HASH_BUFLEN 256
#define HASH_LONG_KEY 64
#define HASH_MAX_KEY_SIZE (SHA256_BLOCK_SIZE * 8)
#define HASH_QUEUE_LENGTH 16
#define HASH_DMA_THRESHOLD 50
struct stm32_hash_ctx {
struct stm32_hash_dev *hdev;
unsigned long flags;
u8 key[HASH_MAX_KEY_SIZE];
int keylen;
};
struct stm32_hash_request_ctx {
struct stm32_hash_dev *hdev;
unsigned long flags;
unsigned long op;
u8 digest[SHA256_DIGEST_SIZE] __aligned(sizeof(u32));
size_t digcnt;
size_t bufcnt;
size_t buflen;
/* DMA */
struct scatterlist *sg;
unsigned int offset;
unsigned int total;
struct scatterlist sg_key;
dma_addr_t dma_addr;
size_t dma_ct;
int nents;
u8 data_type;
u8 buffer[HASH_BUFLEN] __aligned(sizeof(u32));
/* Export Context */
u32 *hw_context;
};
struct stm32_hash_algs_info {
struct ahash_alg *algs_list;
size_t size;
};
struct stm32_hash_pdata {
struct stm32_hash_algs_info *algs_info;
size_t algs_info_size;
};
struct stm32_hash_dev {
struct list_head list;
struct device *dev;
struct clk *clk;
struct reset_control *rst;
void __iomem *io_base;
phys_addr_t phys_base;
u32 dma_mode;
u32 dma_maxburst;
spinlock_t lock; /* lock to protect queue */
struct ahash_request *req;
struct crypto_engine *engine;
int err;
unsigned long flags;
struct dma_chan *dma_lch;
struct completion dma_completion;
const struct stm32_hash_pdata *pdata;
};
struct stm32_hash_drv {
struct list_head dev_list;
spinlock_t lock; /* List protection access */
};
static struct stm32_hash_drv stm32_hash = {
.dev_list = LIST_HEAD_INIT(stm32_hash.dev_list),
.lock = __SPIN_LOCK_UNLOCKED(stm32_hash.lock),
};
static void stm32_hash_dma_callback(void *param);
static inline u32 stm32_hash_read(struct stm32_hash_dev *hdev, u32 offset)
{
return readl_relaxed(hdev->io_base + offset);
}
static inline void stm32_hash_write(struct stm32_hash_dev *hdev,
u32 offset, u32 value)
{
writel_relaxed(value, hdev->io_base + offset);
}
static inline int stm32_hash_wait_busy(struct stm32_hash_dev *hdev)
{
u32 status;
return readl_relaxed_poll_timeout(hdev->io_base + HASH_SR, status,
!(status & HASH_SR_BUSY), 10, 10000);
}
static void stm32_hash_set_nblw(struct stm32_hash_dev *hdev, int length)
{
u32 reg;
reg = stm32_hash_read(hdev, HASH_STR);
reg &= ~(HASH_STR_NBLW_MASK);
reg |= (8U * ((length) % 4U));
stm32_hash_write(hdev, HASH_STR, reg);
}
static int stm32_hash_write_key(struct stm32_hash_dev *hdev)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(hdev->req);
struct stm32_hash_ctx *ctx = crypto_ahash_ctx(tfm);
u32 reg;
int keylen = ctx->keylen;
void *key = ctx->key;
if (ke
|