162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Support for OMAP DES and Triple DES HW acceleration. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2013 Texas Instruments Incorporated 662306a36Sopenharmony_ci * Author: Joel Fernandes <joelf@ti.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#define pr_fmt(fmt) "%s: " fmt, __func__ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#ifdef DEBUG 1262306a36Sopenharmony_ci#define prn(num) printk(#num "=%d\n", num) 1362306a36Sopenharmony_ci#define prx(num) printk(#num "=%x\n", num) 1462306a36Sopenharmony_ci#else 1562306a36Sopenharmony_ci#define prn(num) do { } while (0) 1662306a36Sopenharmony_ci#define prx(num) do { } while (0) 1762306a36Sopenharmony_ci#endif 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <crypto/engine.h> 2062306a36Sopenharmony_ci#include <crypto/internal/des.h> 2162306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 2262306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 2362306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2462306a36Sopenharmony_ci#include <linux/dmaengine.h> 2562306a36Sopenharmony_ci#include <linux/err.h> 2662306a36Sopenharmony_ci#include <linux/init.h> 2762306a36Sopenharmony_ci#include <linux/interrupt.h> 2862306a36Sopenharmony_ci#include <linux/io.h> 2962306a36Sopenharmony_ci#include <linux/kernel.h> 3062306a36Sopenharmony_ci#include <linux/module.h> 3162306a36Sopenharmony_ci#include <linux/of.h> 3262306a36Sopenharmony_ci#include <linux/platform_device.h> 3362306a36Sopenharmony_ci#include <linux/pm_runtime.h> 3462306a36Sopenharmony_ci#include <linux/scatterlist.h> 3562306a36Sopenharmony_ci#include <linux/string.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include "omap-crypto.h" 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define DST_MAXBURST 2 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define DES_BLOCK_WORDS (DES_BLOCK_SIZE >> 2) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define _calc_walked(inout) (dd->inout##_walk.offset - dd->inout##_sg->offset) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define DES_REG_KEY(dd, x) ((dd)->pdata->key_ofs - \ 4662306a36Sopenharmony_ci ((x ^ 0x01) * 0x04)) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define DES_REG_IV(dd, x) ((dd)->pdata->iv_ofs + ((x) * 0x04)) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define DES_REG_CTRL(dd) ((dd)->pdata->ctrl_ofs) 5162306a36Sopenharmony_ci#define DES_REG_CTRL_CBC BIT(4) 5262306a36Sopenharmony_ci#define DES_REG_CTRL_TDES BIT(3) 5362306a36Sopenharmony_ci#define DES_REG_CTRL_DIRECTION BIT(2) 5462306a36Sopenharmony_ci#define DES_REG_CTRL_INPUT_READY BIT(1) 5562306a36Sopenharmony_ci#define DES_REG_CTRL_OUTPUT_READY BIT(0) 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define DES_REG_DATA_N(dd, x) ((dd)->pdata->data_ofs + ((x) * 0x04)) 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define DES_REG_REV(dd) ((dd)->pdata->rev_ofs) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define DES_REG_MASK(dd) ((dd)->pdata->mask_ofs) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define DES_REG_LENGTH_N(x) (0x24 + ((x) * 0x04)) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define DES_REG_IRQ_STATUS(dd) ((dd)->pdata->irq_status_ofs) 6662306a36Sopenharmony_ci#define DES_REG_IRQ_ENABLE(dd) ((dd)->pdata->irq_enable_ofs) 6762306a36Sopenharmony_ci#define DES_REG_IRQ_DATA_IN BIT(1) 6862306a36Sopenharmony_ci#define DES_REG_IRQ_DATA_OUT BIT(2) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define FLAGS_MODE_MASK 0x000f 7162306a36Sopenharmony_ci#define FLAGS_ENCRYPT BIT(0) 7262306a36Sopenharmony_ci#define FLAGS_CBC BIT(1) 7362306a36Sopenharmony_ci#define FLAGS_INIT BIT(4) 7462306a36Sopenharmony_ci#define FLAGS_BUSY BIT(6) 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define DEFAULT_AUTOSUSPEND_DELAY 1000 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define FLAGS_IN_DATA_ST_SHIFT 8 7962306a36Sopenharmony_ci#define FLAGS_OUT_DATA_ST_SHIFT 10 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistruct omap_des_ctx { 8262306a36Sopenharmony_ci struct omap_des_dev *dd; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci int keylen; 8562306a36Sopenharmony_ci __le32 key[(3 * DES_KEY_SIZE) / sizeof(u32)]; 8662306a36Sopenharmony_ci unsigned long flags; 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistruct omap_des_reqctx { 9062306a36Sopenharmony_ci unsigned long mode; 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define OMAP_DES_QUEUE_LENGTH 1 9462306a36Sopenharmony_ci#define OMAP_DES_CACHE_SIZE 0 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistruct omap_des_algs_info { 9762306a36Sopenharmony_ci struct skcipher_engine_alg *algs_list; 9862306a36Sopenharmony_ci unsigned int size; 9962306a36Sopenharmony_ci unsigned int registered; 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistruct omap_des_pdata { 10362306a36Sopenharmony_ci struct omap_des_algs_info *algs_info; 10462306a36Sopenharmony_ci unsigned int algs_info_size; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci void (*trigger)(struct omap_des_dev *dd, int length); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci u32 key_ofs; 10962306a36Sopenharmony_ci u32 iv_ofs; 11062306a36Sopenharmony_ci u32 ctrl_ofs; 11162306a36Sopenharmony_ci u32 data_ofs; 11262306a36Sopenharmony_ci u32 rev_ofs; 11362306a36Sopenharmony_ci u32 mask_ofs; 11462306a36Sopenharmony_ci u32 irq_enable_ofs; 11562306a36Sopenharmony_ci u32 irq_status_ofs; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci u32 dma_enable_in; 11862306a36Sopenharmony_ci u32 dma_enable_out; 11962306a36Sopenharmony_ci u32 dma_start; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci u32 major_mask; 12262306a36Sopenharmony_ci u32 major_shift; 12362306a36Sopenharmony_ci u32 minor_mask; 12462306a36Sopenharmony_ci u32 minor_shift; 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistruct omap_des_dev { 12862306a36Sopenharmony_ci struct list_head list; 12962306a36Sopenharmony_ci unsigned long phys_base; 13062306a36Sopenharmony_ci void __iomem *io_base; 13162306a36Sopenharmony_ci struct omap_des_ctx *ctx; 13262306a36Sopenharmony_ci struct device *dev; 13362306a36Sopenharmony_ci unsigned long flags; 13462306a36Sopenharmony_ci int err; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci struct tasklet_struct done_task; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci struct skcipher_request *req; 13962306a36Sopenharmony_ci struct crypto_engine *engine; 14062306a36Sopenharmony_ci /* 14162306a36Sopenharmony_ci * total is used by PIO mode for book keeping so introduce 14262306a36Sopenharmony_ci * variable total_save as need it to calc page_order 14362306a36Sopenharmony_ci */ 14462306a36Sopenharmony_ci size_t total; 14562306a36Sopenharmony_ci size_t total_save; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci struct scatterlist *in_sg; 14862306a36Sopenharmony_ci struct scatterlist *out_sg; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* Buffers for copying for unaligned cases */ 15162306a36Sopenharmony_ci struct scatterlist in_sgl; 15262306a36Sopenharmony_ci struct scatterlist out_sgl; 15362306a36Sopenharmony_ci struct scatterlist *orig_out; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci struct scatter_walk in_walk; 15662306a36Sopenharmony_ci struct scatter_walk out_walk; 15762306a36Sopenharmony_ci struct dma_chan *dma_lch_in; 15862306a36Sopenharmony_ci struct dma_chan *dma_lch_out; 15962306a36Sopenharmony_ci int in_sg_len; 16062306a36Sopenharmony_ci int out_sg_len; 16162306a36Sopenharmony_ci int pio_only; 16262306a36Sopenharmony_ci const struct omap_des_pdata *pdata; 16362306a36Sopenharmony_ci}; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* keep registered devices data here */ 16662306a36Sopenharmony_cistatic LIST_HEAD(dev_list); 16762306a36Sopenharmony_cistatic DEFINE_SPINLOCK(list_lock); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci#ifdef DEBUG 17062306a36Sopenharmony_ci#define omap_des_read(dd, offset) \ 17162306a36Sopenharmony_ci ({ \ 17262306a36Sopenharmony_ci int _read_ret; \ 17362306a36Sopenharmony_ci _read_ret = __raw_readl(dd->io_base + offset); \ 17462306a36Sopenharmony_ci pr_err("omap_des_read(" #offset "=%#x)= %#x\n", \ 17562306a36Sopenharmony_ci offset, _read_ret); \ 17662306a36Sopenharmony_ci _read_ret; \ 17762306a36Sopenharmony_ci }) 17862306a36Sopenharmony_ci#else 17962306a36Sopenharmony_cistatic inline u32 omap_des_read(struct omap_des_dev *dd, u32 offset) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci return __raw_readl(dd->io_base + offset); 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci#endif 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci#ifdef DEBUG 18662306a36Sopenharmony_ci#define omap_des_write(dd, offset, value) \ 18762306a36Sopenharmony_ci do { \ 18862306a36Sopenharmony_ci pr_err("omap_des_write(" #offset "=%#x) value=%#x\n", \ 18962306a36Sopenharmony_ci offset, value); \ 19062306a36Sopenharmony_ci __raw_writel(value, dd->io_base + offset); \ 19162306a36Sopenharmony_ci } while (0) 19262306a36Sopenharmony_ci#else 19362306a36Sopenharmony_cistatic inline void omap_des_write(struct omap_des_dev *dd, u32 offset, 19462306a36Sopenharmony_ci u32 value) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci __raw_writel(value, dd->io_base + offset); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci#endif 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic inline void omap_des_write_mask(struct omap_des_dev *dd, u32 offset, 20162306a36Sopenharmony_ci u32 value, u32 mask) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci u32 val; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci val = omap_des_read(dd, offset); 20662306a36Sopenharmony_ci val &= ~mask; 20762306a36Sopenharmony_ci val |= value; 20862306a36Sopenharmony_ci omap_des_write(dd, offset, val); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void omap_des_write_n(struct omap_des_dev *dd, u32 offset, 21262306a36Sopenharmony_ci u32 *value, int count) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci for (; count--; value++, offset += 4) 21562306a36Sopenharmony_ci omap_des_write(dd, offset, *value); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic int omap_des_hw_init(struct omap_des_dev *dd) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci int err; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* 22362306a36Sopenharmony_ci * clocks are enabled when request starts and disabled when finished. 22462306a36Sopenharmony_ci * It may be long delays between requests. 22562306a36Sopenharmony_ci * Device might go to off mode to save power. 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_ci err = pm_runtime_resume_and_get(dd->dev); 22862306a36Sopenharmony_ci if (err < 0) { 22962306a36Sopenharmony_ci dev_err(dd->dev, "%s: failed to get_sync(%d)\n", __func__, err); 23062306a36Sopenharmony_ci return err; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (!(dd->flags & FLAGS_INIT)) { 23462306a36Sopenharmony_ci dd->flags |= FLAGS_INIT; 23562306a36Sopenharmony_ci dd->err = 0; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int omap_des_write_ctrl(struct omap_des_dev *dd) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci unsigned int key32; 24462306a36Sopenharmony_ci int i, err; 24562306a36Sopenharmony_ci u32 val = 0, mask = 0; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci err = omap_des_hw_init(dd); 24862306a36Sopenharmony_ci if (err) 24962306a36Sopenharmony_ci return err; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci key32 = dd->ctx->keylen / sizeof(u32); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* it seems a key should always be set even if it has not changed */ 25462306a36Sopenharmony_ci for (i = 0; i < key32; i++) { 25562306a36Sopenharmony_ci omap_des_write(dd, DES_REG_KEY(dd, i), 25662306a36Sopenharmony_ci __le32_to_cpu(dd->ctx->key[i])); 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if ((dd->flags & FLAGS_CBC) && dd->req->iv) 26062306a36Sopenharmony_ci omap_des_write_n(dd, DES_REG_IV(dd, 0), (void *)dd->req->iv, 2); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (dd->flags & FLAGS_CBC) 26362306a36Sopenharmony_ci val |= DES_REG_CTRL_CBC; 26462306a36Sopenharmony_ci if (dd->flags & FLAGS_ENCRYPT) 26562306a36Sopenharmony_ci val |= DES_REG_CTRL_DIRECTION; 26662306a36Sopenharmony_ci if (key32 == 6) 26762306a36Sopenharmony_ci val |= DES_REG_CTRL_TDES; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci mask |= DES_REG_CTRL_CBC | DES_REG_CTRL_DIRECTION | DES_REG_CTRL_TDES; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci omap_des_write_mask(dd, DES_REG_CTRL(dd), val, mask); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return 0; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic void omap_des_dma_trigger_omap4(struct omap_des_dev *dd, int length) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci u32 mask, val; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci omap_des_write(dd, DES_REG_LENGTH_N(0), length); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci val = dd->pdata->dma_start; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (dd->dma_lch_out != NULL) 28562306a36Sopenharmony_ci val |= dd->pdata->dma_enable_out; 28662306a36Sopenharmony_ci if (dd->dma_lch_in != NULL) 28762306a36Sopenharmony_ci val |= dd->pdata->dma_enable_in; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci mask = dd->pdata->dma_enable_out | dd->pdata->dma_enable_in | 29062306a36Sopenharmony_ci dd->pdata->dma_start; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci omap_des_write_mask(dd, DES_REG_MASK(dd), val, mask); 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic void omap_des_dma_stop(struct omap_des_dev *dd) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci u32 mask; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci mask = dd->pdata->dma_enable_out | dd->pdata->dma_enable_in | 30062306a36Sopenharmony_ci dd->pdata->dma_start; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci omap_des_write_mask(dd, DES_REG_MASK(dd), 0, mask); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic struct omap_des_dev *omap_des_find_dev(struct omap_des_ctx *ctx) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct omap_des_dev *dd = NULL, *tmp; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci spin_lock_bh(&list_lock); 31062306a36Sopenharmony_ci if (!ctx->dd) { 31162306a36Sopenharmony_ci list_for_each_entry(tmp, &dev_list, list) { 31262306a36Sopenharmony_ci /* FIXME: take fist available des core */ 31362306a36Sopenharmony_ci dd = tmp; 31462306a36Sopenharmony_ci break; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci ctx->dd = dd; 31762306a36Sopenharmony_ci } else { 31862306a36Sopenharmony_ci /* already found before */ 31962306a36Sopenharmony_ci dd = ctx->dd; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci spin_unlock_bh(&list_lock); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return dd; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic void omap_des_dma_out_callback(void *data) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct omap_des_dev *dd = data; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* dma_lch_out - completed */ 33162306a36Sopenharmony_ci tasklet_schedule(&dd->done_task); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic int omap_des_dma_init(struct omap_des_dev *dd) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci int err; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci dd->dma_lch_out = NULL; 33962306a36Sopenharmony_ci dd->dma_lch_in = NULL; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci dd->dma_lch_in = dma_request_chan(dd->dev, "rx"); 34262306a36Sopenharmony_ci if (IS_ERR(dd->dma_lch_in)) { 34362306a36Sopenharmony_ci dev_err(dd->dev, "Unable to request in DMA channel\n"); 34462306a36Sopenharmony_ci return PTR_ERR(dd->dma_lch_in); 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci dd->dma_lch_out = dma_request_chan(dd->dev, "tx"); 34862306a36Sopenharmony_ci if (IS_ERR(dd->dma_lch_out)) { 34962306a36Sopenharmony_ci dev_err(dd->dev, "Unable to request out DMA channel\n"); 35062306a36Sopenharmony_ci err = PTR_ERR(dd->dma_lch_out); 35162306a36Sopenharmony_ci goto err_dma_out; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci return 0; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cierr_dma_out: 35762306a36Sopenharmony_ci dma_release_channel(dd->dma_lch_in); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return err; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic void omap_des_dma_cleanup(struct omap_des_dev *dd) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci if (dd->pio_only) 36562306a36Sopenharmony_ci return; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci dma_release_channel(dd->dma_lch_out); 36862306a36Sopenharmony_ci dma_release_channel(dd->dma_lch_in); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic int omap_des_crypt_dma(struct crypto_tfm *tfm, 37262306a36Sopenharmony_ci struct scatterlist *in_sg, struct scatterlist *out_sg, 37362306a36Sopenharmony_ci int in_sg_len, int out_sg_len) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct omap_des_ctx *ctx = crypto_tfm_ctx(tfm); 37662306a36Sopenharmony_ci struct omap_des_dev *dd = ctx->dd; 37762306a36Sopenharmony_ci struct dma_async_tx_descriptor *tx_in, *tx_out; 37862306a36Sopenharmony_ci struct dma_slave_config cfg; 37962306a36Sopenharmony_ci int ret; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (dd->pio_only) { 38262306a36Sopenharmony_ci scatterwalk_start(&dd->in_walk, dd->in_sg); 38362306a36Sopenharmony_ci scatterwalk_start(&dd->out_walk, dd->out_sg); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* Enable DATAIN interrupt and let it take 38662306a36Sopenharmony_ci care of the rest */ 38762306a36Sopenharmony_ci omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x2); 38862306a36Sopenharmony_ci return 0; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci dma_sync_sg_for_device(dd->dev, dd->in_sg, in_sg_len, DMA_TO_DEVICE); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci memset(&cfg, 0, sizeof(cfg)); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci cfg.src_addr = dd->phys_base + DES_REG_DATA_N(dd, 0); 39662306a36Sopenharmony_ci cfg.dst_addr = dd->phys_base + DES_REG_DATA_N(dd, 0); 39762306a36Sopenharmony_ci cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 39862306a36Sopenharmony_ci cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 39962306a36Sopenharmony_ci cfg.src_maxburst = DST_MAXBURST; 40062306a36Sopenharmony_ci cfg.dst_maxburst = DST_MAXBURST; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* IN */ 40362306a36Sopenharmony_ci ret = dmaengine_slave_config(dd->dma_lch_in, &cfg); 40462306a36Sopenharmony_ci if (ret) { 40562306a36Sopenharmony_ci dev_err(dd->dev, "can't configure IN dmaengine slave: %d\n", 40662306a36Sopenharmony_ci ret); 40762306a36Sopenharmony_ci return ret; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci tx_in = dmaengine_prep_slave_sg(dd->dma_lch_in, in_sg, in_sg_len, 41162306a36Sopenharmony_ci DMA_MEM_TO_DEV, 41262306a36Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 41362306a36Sopenharmony_ci if (!tx_in) { 41462306a36Sopenharmony_ci dev_err(dd->dev, "IN prep_slave_sg() failed\n"); 41562306a36Sopenharmony_ci return -EINVAL; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci /* No callback necessary */ 41962306a36Sopenharmony_ci tx_in->callback_param = dd; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* OUT */ 42262306a36Sopenharmony_ci ret = dmaengine_slave_config(dd->dma_lch_out, &cfg); 42362306a36Sopenharmony_ci if (ret) { 42462306a36Sopenharmony_ci dev_err(dd->dev, "can't configure OUT dmaengine slave: %d\n", 42562306a36Sopenharmony_ci ret); 42662306a36Sopenharmony_ci return ret; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci tx_out = dmaengine_prep_slave_sg(dd->dma_lch_out, out_sg, out_sg_len, 43062306a36Sopenharmony_ci DMA_DEV_TO_MEM, 43162306a36Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 43262306a36Sopenharmony_ci if (!tx_out) { 43362306a36Sopenharmony_ci dev_err(dd->dev, "OUT prep_slave_sg() failed\n"); 43462306a36Sopenharmony_ci return -EINVAL; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci tx_out->callback = omap_des_dma_out_callback; 43862306a36Sopenharmony_ci tx_out->callback_param = dd; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci dmaengine_submit(tx_in); 44162306a36Sopenharmony_ci dmaengine_submit(tx_out); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci dma_async_issue_pending(dd->dma_lch_in); 44462306a36Sopenharmony_ci dma_async_issue_pending(dd->dma_lch_out); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* start DMA */ 44762306a36Sopenharmony_ci dd->pdata->trigger(dd, dd->total); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci return 0; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic int omap_des_crypt_dma_start(struct omap_des_dev *dd) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct crypto_tfm *tfm = crypto_skcipher_tfm( 45562306a36Sopenharmony_ci crypto_skcipher_reqtfm(dd->req)); 45662306a36Sopenharmony_ci int err; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci pr_debug("total: %zd\n", dd->total); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (!dd->pio_only) { 46162306a36Sopenharmony_ci err = dma_map_sg(dd->dev, dd->in_sg, dd->in_sg_len, 46262306a36Sopenharmony_ci DMA_TO_DEVICE); 46362306a36Sopenharmony_ci if (!err) { 46462306a36Sopenharmony_ci dev_err(dd->dev, "dma_map_sg() error\n"); 46562306a36Sopenharmony_ci return -EINVAL; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci err = dma_map_sg(dd->dev, dd->out_sg, dd->out_sg_len, 46962306a36Sopenharmony_ci DMA_FROM_DEVICE); 47062306a36Sopenharmony_ci if (!err) { 47162306a36Sopenharmony_ci dev_err(dd->dev, "dma_map_sg() error\n"); 47262306a36Sopenharmony_ci return -EINVAL; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci err = omap_des_crypt_dma(tfm, dd->in_sg, dd->out_sg, dd->in_sg_len, 47762306a36Sopenharmony_ci dd->out_sg_len); 47862306a36Sopenharmony_ci if (err && !dd->pio_only) { 47962306a36Sopenharmony_ci dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE); 48062306a36Sopenharmony_ci dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len, 48162306a36Sopenharmony_ci DMA_FROM_DEVICE); 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci return err; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic void omap_des_finish_req(struct omap_des_dev *dd, int err) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct skcipher_request *req = dd->req; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci pr_debug("err: %d\n", err); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci crypto_finalize_skcipher_request(dd->engine, req, err); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci pm_runtime_mark_last_busy(dd->dev); 49662306a36Sopenharmony_ci pm_runtime_put_autosuspend(dd->dev); 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic int omap_des_crypt_dma_stop(struct omap_des_dev *dd) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci pr_debug("total: %zd\n", dd->total); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci omap_des_dma_stop(dd); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci dmaengine_terminate_all(dd->dma_lch_in); 50662306a36Sopenharmony_ci dmaengine_terminate_all(dd->dma_lch_out); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci return 0; 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic int omap_des_handle_queue(struct omap_des_dev *dd, 51262306a36Sopenharmony_ci struct skcipher_request *req) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci if (req) 51562306a36Sopenharmony_ci return crypto_transfer_skcipher_request_to_engine(dd->engine, req); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci return 0; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic int omap_des_prepare_req(struct skcipher_request *req, 52162306a36Sopenharmony_ci struct omap_des_dev *dd) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci struct omap_des_ctx *ctx = crypto_skcipher_ctx( 52462306a36Sopenharmony_ci crypto_skcipher_reqtfm(req)); 52562306a36Sopenharmony_ci struct omap_des_reqctx *rctx; 52662306a36Sopenharmony_ci int ret; 52762306a36Sopenharmony_ci u16 flags; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci /* assign new request to device */ 53062306a36Sopenharmony_ci dd->req = req; 53162306a36Sopenharmony_ci dd->total = req->cryptlen; 53262306a36Sopenharmony_ci dd->total_save = req->cryptlen; 53362306a36Sopenharmony_ci dd->in_sg = req->src; 53462306a36Sopenharmony_ci dd->out_sg = req->dst; 53562306a36Sopenharmony_ci dd->orig_out = req->dst; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci flags = OMAP_CRYPTO_COPY_DATA; 53862306a36Sopenharmony_ci if (req->src == req->dst) 53962306a36Sopenharmony_ci flags |= OMAP_CRYPTO_FORCE_COPY; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci ret = omap_crypto_align_sg(&dd->in_sg, dd->total, DES_BLOCK_SIZE, 54262306a36Sopenharmony_ci &dd->in_sgl, flags, 54362306a36Sopenharmony_ci FLAGS_IN_DATA_ST_SHIFT, &dd->flags); 54462306a36Sopenharmony_ci if (ret) 54562306a36Sopenharmony_ci return ret; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci ret = omap_crypto_align_sg(&dd->out_sg, dd->total, DES_BLOCK_SIZE, 54862306a36Sopenharmony_ci &dd->out_sgl, 0, 54962306a36Sopenharmony_ci FLAGS_OUT_DATA_ST_SHIFT, &dd->flags); 55062306a36Sopenharmony_ci if (ret) 55162306a36Sopenharmony_ci return ret; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci dd->in_sg_len = sg_nents_for_len(dd->in_sg, dd->total); 55462306a36Sopenharmony_ci if (dd->in_sg_len < 0) 55562306a36Sopenharmony_ci return dd->in_sg_len; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci dd->out_sg_len = sg_nents_for_len(dd->out_sg, dd->total); 55862306a36Sopenharmony_ci if (dd->out_sg_len < 0) 55962306a36Sopenharmony_ci return dd->out_sg_len; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci rctx = skcipher_request_ctx(req); 56262306a36Sopenharmony_ci ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); 56362306a36Sopenharmony_ci rctx->mode &= FLAGS_MODE_MASK; 56462306a36Sopenharmony_ci dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci dd->ctx = ctx; 56762306a36Sopenharmony_ci ctx->dd = dd; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci return omap_des_write_ctrl(dd); 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cistatic int omap_des_crypt_req(struct crypto_engine *engine, 57362306a36Sopenharmony_ci void *areq) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci struct skcipher_request *req = container_of(areq, struct skcipher_request, base); 57662306a36Sopenharmony_ci struct omap_des_ctx *ctx = crypto_skcipher_ctx( 57762306a36Sopenharmony_ci crypto_skcipher_reqtfm(req)); 57862306a36Sopenharmony_ci struct omap_des_dev *dd = omap_des_find_dev(ctx); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if (!dd) 58162306a36Sopenharmony_ci return -ENODEV; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci return omap_des_prepare_req(req, dd) ?: 58462306a36Sopenharmony_ci omap_des_crypt_dma_start(dd); 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic void omap_des_done_task(unsigned long data) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci struct omap_des_dev *dd = (struct omap_des_dev *)data; 59062306a36Sopenharmony_ci int i; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci pr_debug("enter done_task\n"); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (!dd->pio_only) { 59562306a36Sopenharmony_ci dma_sync_sg_for_device(dd->dev, dd->out_sg, dd->out_sg_len, 59662306a36Sopenharmony_ci DMA_FROM_DEVICE); 59762306a36Sopenharmony_ci dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE); 59862306a36Sopenharmony_ci dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len, 59962306a36Sopenharmony_ci DMA_FROM_DEVICE); 60062306a36Sopenharmony_ci omap_des_crypt_dma_stop(dd); 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci omap_crypto_cleanup(&dd->in_sgl, NULL, 0, dd->total_save, 60462306a36Sopenharmony_ci FLAGS_IN_DATA_ST_SHIFT, dd->flags); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci omap_crypto_cleanup(&dd->out_sgl, dd->orig_out, 0, dd->total_save, 60762306a36Sopenharmony_ci FLAGS_OUT_DATA_ST_SHIFT, dd->flags); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci if ((dd->flags & FLAGS_CBC) && dd->req->iv) 61062306a36Sopenharmony_ci for (i = 0; i < 2; i++) 61162306a36Sopenharmony_ci ((u32 *)dd->req->iv)[i] = 61262306a36Sopenharmony_ci omap_des_read(dd, DES_REG_IV(dd, i)); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci omap_des_finish_req(dd, 0); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci pr_debug("exit\n"); 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic int omap_des_crypt(struct skcipher_request *req, unsigned long mode) 62062306a36Sopenharmony_ci{ 62162306a36Sopenharmony_ci struct omap_des_ctx *ctx = crypto_skcipher_ctx( 62262306a36Sopenharmony_ci crypto_skcipher_reqtfm(req)); 62362306a36Sopenharmony_ci struct omap_des_reqctx *rctx = skcipher_request_ctx(req); 62462306a36Sopenharmony_ci struct omap_des_dev *dd; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci pr_debug("nbytes: %d, enc: %d, cbc: %d\n", req->cryptlen, 62762306a36Sopenharmony_ci !!(mode & FLAGS_ENCRYPT), 62862306a36Sopenharmony_ci !!(mode & FLAGS_CBC)); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (!req->cryptlen) 63162306a36Sopenharmony_ci return 0; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci if (!IS_ALIGNED(req->cryptlen, DES_BLOCK_SIZE)) 63462306a36Sopenharmony_ci return -EINVAL; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci dd = omap_des_find_dev(ctx); 63762306a36Sopenharmony_ci if (!dd) 63862306a36Sopenharmony_ci return -ENODEV; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci rctx->mode = mode; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci return omap_des_handle_queue(dd, req); 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci/* ********************** ALG API ************************************ */ 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cistatic int omap_des_setkey(struct crypto_skcipher *cipher, const u8 *key, 64862306a36Sopenharmony_ci unsigned int keylen) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci struct omap_des_ctx *ctx = crypto_skcipher_ctx(cipher); 65162306a36Sopenharmony_ci int err; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci pr_debug("enter, keylen: %d\n", keylen); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci err = verify_skcipher_des_key(cipher, key); 65662306a36Sopenharmony_ci if (err) 65762306a36Sopenharmony_ci return err; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci memcpy(ctx->key, key, keylen); 66062306a36Sopenharmony_ci ctx->keylen = keylen; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci return 0; 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic int omap_des3_setkey(struct crypto_skcipher *cipher, const u8 *key, 66662306a36Sopenharmony_ci unsigned int keylen) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci struct omap_des_ctx *ctx = crypto_skcipher_ctx(cipher); 66962306a36Sopenharmony_ci int err; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci pr_debug("enter, keylen: %d\n", keylen); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci err = verify_skcipher_des3_key(cipher, key); 67462306a36Sopenharmony_ci if (err) 67562306a36Sopenharmony_ci return err; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci memcpy(ctx->key, key, keylen); 67862306a36Sopenharmony_ci ctx->keylen = keylen; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic int omap_des_ecb_encrypt(struct skcipher_request *req) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci return omap_des_crypt(req, FLAGS_ENCRYPT); 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic int omap_des_ecb_decrypt(struct skcipher_request *req) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci return omap_des_crypt(req, 0); 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cistatic int omap_des_cbc_encrypt(struct skcipher_request *req) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci return omap_des_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC); 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic int omap_des_cbc_decrypt(struct skcipher_request *req) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci return omap_des_crypt(req, FLAGS_CBC); 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_cistatic int omap_des_init_tfm(struct crypto_skcipher *tfm) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci pr_debug("enter\n"); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct omap_des_reqctx)); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci return 0; 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci/* ********************** ALGS ************************************ */ 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cistatic struct skcipher_engine_alg algs_ecb_cbc[] = { 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci .base = { 71762306a36Sopenharmony_ci .base.cra_name = "ecb(des)", 71862306a36Sopenharmony_ci .base.cra_driver_name = "ecb-des-omap", 71962306a36Sopenharmony_ci .base.cra_priority = 300, 72062306a36Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 72162306a36Sopenharmony_ci CRYPTO_ALG_ASYNC, 72262306a36Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 72362306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct omap_des_ctx), 72462306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 72762306a36Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 72862306a36Sopenharmony_ci .setkey = omap_des_setkey, 72962306a36Sopenharmony_ci .encrypt = omap_des_ecb_encrypt, 73062306a36Sopenharmony_ci .decrypt = omap_des_ecb_decrypt, 73162306a36Sopenharmony_ci .init = omap_des_init_tfm, 73262306a36Sopenharmony_ci }, 73362306a36Sopenharmony_ci .op.do_one_request = omap_des_crypt_req, 73462306a36Sopenharmony_ci}, 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci .base = { 73762306a36Sopenharmony_ci .base.cra_name = "cbc(des)", 73862306a36Sopenharmony_ci .base.cra_driver_name = "cbc-des-omap", 73962306a36Sopenharmony_ci .base.cra_priority = 300, 74062306a36Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 74162306a36Sopenharmony_ci CRYPTO_ALG_ASYNC, 74262306a36Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 74362306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct omap_des_ctx), 74462306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 74762306a36Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 74862306a36Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 74962306a36Sopenharmony_ci .setkey = omap_des_setkey, 75062306a36Sopenharmony_ci .encrypt = omap_des_cbc_encrypt, 75162306a36Sopenharmony_ci .decrypt = omap_des_cbc_decrypt, 75262306a36Sopenharmony_ci .init = omap_des_init_tfm, 75362306a36Sopenharmony_ci }, 75462306a36Sopenharmony_ci .op.do_one_request = omap_des_crypt_req, 75562306a36Sopenharmony_ci}, 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci .base = { 75862306a36Sopenharmony_ci .base.cra_name = "ecb(des3_ede)", 75962306a36Sopenharmony_ci .base.cra_driver_name = "ecb-des3-omap", 76062306a36Sopenharmony_ci .base.cra_priority = 300, 76162306a36Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 76262306a36Sopenharmony_ci CRYPTO_ALG_ASYNC, 76362306a36Sopenharmony_ci .base.cra_blocksize = DES3_EDE_BLOCK_SIZE, 76462306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct omap_des_ctx), 76562306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci .min_keysize = DES3_EDE_KEY_SIZE, 76862306a36Sopenharmony_ci .max_keysize = DES3_EDE_KEY_SIZE, 76962306a36Sopenharmony_ci .setkey = omap_des3_setkey, 77062306a36Sopenharmony_ci .encrypt = omap_des_ecb_encrypt, 77162306a36Sopenharmony_ci .decrypt = omap_des_ecb_decrypt, 77262306a36Sopenharmony_ci .init = omap_des_init_tfm, 77362306a36Sopenharmony_ci }, 77462306a36Sopenharmony_ci .op.do_one_request = omap_des_crypt_req, 77562306a36Sopenharmony_ci}, 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci .base = { 77862306a36Sopenharmony_ci .base.cra_name = "cbc(des3_ede)", 77962306a36Sopenharmony_ci .base.cra_driver_name = "cbc-des3-omap", 78062306a36Sopenharmony_ci .base.cra_priority = 300, 78162306a36Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 78262306a36Sopenharmony_ci CRYPTO_ALG_ASYNC, 78362306a36Sopenharmony_ci .base.cra_blocksize = DES3_EDE_BLOCK_SIZE, 78462306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct omap_des_ctx), 78562306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci .min_keysize = DES3_EDE_KEY_SIZE, 78862306a36Sopenharmony_ci .max_keysize = DES3_EDE_KEY_SIZE, 78962306a36Sopenharmony_ci .ivsize = DES3_EDE_BLOCK_SIZE, 79062306a36Sopenharmony_ci .setkey = omap_des3_setkey, 79162306a36Sopenharmony_ci .encrypt = omap_des_cbc_encrypt, 79262306a36Sopenharmony_ci .decrypt = omap_des_cbc_decrypt, 79362306a36Sopenharmony_ci .init = omap_des_init_tfm, 79462306a36Sopenharmony_ci }, 79562306a36Sopenharmony_ci .op.do_one_request = omap_des_crypt_req, 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci}; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_cistatic struct omap_des_algs_info omap_des_algs_info_ecb_cbc[] = { 80062306a36Sopenharmony_ci { 80162306a36Sopenharmony_ci .algs_list = algs_ecb_cbc, 80262306a36Sopenharmony_ci .size = ARRAY_SIZE(algs_ecb_cbc), 80362306a36Sopenharmony_ci }, 80462306a36Sopenharmony_ci}; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci#ifdef CONFIG_OF 80762306a36Sopenharmony_cistatic const struct omap_des_pdata omap_des_pdata_omap4 = { 80862306a36Sopenharmony_ci .algs_info = omap_des_algs_info_ecb_cbc, 80962306a36Sopenharmony_ci .algs_info_size = ARRAY_SIZE(omap_des_algs_info_ecb_cbc), 81062306a36Sopenharmony_ci .trigger = omap_des_dma_trigger_omap4, 81162306a36Sopenharmony_ci .key_ofs = 0x14, 81262306a36Sopenharmony_ci .iv_ofs = 0x18, 81362306a36Sopenharmony_ci .ctrl_ofs = 0x20, 81462306a36Sopenharmony_ci .data_ofs = 0x28, 81562306a36Sopenharmony_ci .rev_ofs = 0x30, 81662306a36Sopenharmony_ci .mask_ofs = 0x34, 81762306a36Sopenharmony_ci .irq_status_ofs = 0x3c, 81862306a36Sopenharmony_ci .irq_enable_ofs = 0x40, 81962306a36Sopenharmony_ci .dma_enable_in = BIT(5), 82062306a36Sopenharmony_ci .dma_enable_out = BIT(6), 82162306a36Sopenharmony_ci .major_mask = 0x0700, 82262306a36Sopenharmony_ci .major_shift = 8, 82362306a36Sopenharmony_ci .minor_mask = 0x003f, 82462306a36Sopenharmony_ci .minor_shift = 0, 82562306a36Sopenharmony_ci}; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cistatic irqreturn_t omap_des_irq(int irq, void *dev_id) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci struct omap_des_dev *dd = dev_id; 83062306a36Sopenharmony_ci u32 status, i; 83162306a36Sopenharmony_ci u32 *src, *dst; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci status = omap_des_read(dd, DES_REG_IRQ_STATUS(dd)); 83462306a36Sopenharmony_ci if (status & DES_REG_IRQ_DATA_IN) { 83562306a36Sopenharmony_ci omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x0); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci BUG_ON(!dd->in_sg); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci BUG_ON(_calc_walked(in) > dd->in_sg->length); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci src = sg_virt(dd->in_sg) + _calc_walked(in); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci for (i = 0; i < DES_BLOCK_WORDS; i++) { 84462306a36Sopenharmony_ci omap_des_write(dd, DES_REG_DATA_N(dd, i), *src); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci scatterwalk_advance(&dd->in_walk, 4); 84762306a36Sopenharmony_ci if (dd->in_sg->length == _calc_walked(in)) { 84862306a36Sopenharmony_ci dd->in_sg = sg_next(dd->in_sg); 84962306a36Sopenharmony_ci if (dd->in_sg) { 85062306a36Sopenharmony_ci scatterwalk_start(&dd->in_walk, 85162306a36Sopenharmony_ci dd->in_sg); 85262306a36Sopenharmony_ci src = sg_virt(dd->in_sg) + 85362306a36Sopenharmony_ci _calc_walked(in); 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci } else { 85662306a36Sopenharmony_ci src++; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci /* Clear IRQ status */ 86162306a36Sopenharmony_ci status &= ~DES_REG_IRQ_DATA_IN; 86262306a36Sopenharmony_ci omap_des_write(dd, DES_REG_IRQ_STATUS(dd), status); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* Enable DATA_OUT interrupt */ 86562306a36Sopenharmony_ci omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x4); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci } else if (status & DES_REG_IRQ_DATA_OUT) { 86862306a36Sopenharmony_ci omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x0); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci BUG_ON(!dd->out_sg); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci BUG_ON(_calc_walked(out) > dd->out_sg->length); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci dst = sg_virt(dd->out_sg) + _calc_walked(out); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci for (i = 0; i < DES_BLOCK_WORDS; i++) { 87762306a36Sopenharmony_ci *dst = omap_des_read(dd, DES_REG_DATA_N(dd, i)); 87862306a36Sopenharmony_ci scatterwalk_advance(&dd->out_walk, 4); 87962306a36Sopenharmony_ci if (dd->out_sg->length == _calc_walked(out)) { 88062306a36Sopenharmony_ci dd->out_sg = sg_next(dd->out_sg); 88162306a36Sopenharmony_ci if (dd->out_sg) { 88262306a36Sopenharmony_ci scatterwalk_start(&dd->out_walk, 88362306a36Sopenharmony_ci dd->out_sg); 88462306a36Sopenharmony_ci dst = sg_virt(dd->out_sg) + 88562306a36Sopenharmony_ci _calc_walked(out); 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci } else { 88862306a36Sopenharmony_ci dst++; 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci BUG_ON(dd->total < DES_BLOCK_SIZE); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci dd->total -= DES_BLOCK_SIZE; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci /* Clear IRQ status */ 89762306a36Sopenharmony_ci status &= ~DES_REG_IRQ_DATA_OUT; 89862306a36Sopenharmony_ci omap_des_write(dd, DES_REG_IRQ_STATUS(dd), status); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci if (!dd->total) 90162306a36Sopenharmony_ci /* All bytes read! */ 90262306a36Sopenharmony_ci tasklet_schedule(&dd->done_task); 90362306a36Sopenharmony_ci else 90462306a36Sopenharmony_ci /* Enable DATA_IN interrupt for next block */ 90562306a36Sopenharmony_ci omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x2); 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci return IRQ_HANDLED; 90962306a36Sopenharmony_ci} 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_cistatic const struct of_device_id omap_des_of_match[] = { 91262306a36Sopenharmony_ci { 91362306a36Sopenharmony_ci .compatible = "ti,omap4-des", 91462306a36Sopenharmony_ci .data = &omap_des_pdata_omap4, 91562306a36Sopenharmony_ci }, 91662306a36Sopenharmony_ci {}, 91762306a36Sopenharmony_ci}; 91862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, omap_des_of_match); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_cistatic int omap_des_get_of(struct omap_des_dev *dd, 92162306a36Sopenharmony_ci struct platform_device *pdev) 92262306a36Sopenharmony_ci{ 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci dd->pdata = of_device_get_match_data(&pdev->dev); 92562306a36Sopenharmony_ci if (!dd->pdata) { 92662306a36Sopenharmony_ci dev_err(&pdev->dev, "no compatible OF match\n"); 92762306a36Sopenharmony_ci return -EINVAL; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci return 0; 93162306a36Sopenharmony_ci} 93262306a36Sopenharmony_ci#else 93362306a36Sopenharmony_cistatic int omap_des_get_of(struct omap_des_dev *dd, 93462306a36Sopenharmony_ci struct device *dev) 93562306a36Sopenharmony_ci{ 93662306a36Sopenharmony_ci return -EINVAL; 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci#endif 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic int omap_des_get_pdev(struct omap_des_dev *dd, 94162306a36Sopenharmony_ci struct platform_device *pdev) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci /* non-DT devices get pdata from pdev */ 94462306a36Sopenharmony_ci dd->pdata = pdev->dev.platform_data; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci return 0; 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_cistatic int omap_des_probe(struct platform_device *pdev) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci struct device *dev = &pdev->dev; 95262306a36Sopenharmony_ci struct omap_des_dev *dd; 95362306a36Sopenharmony_ci struct skcipher_engine_alg *algp; 95462306a36Sopenharmony_ci struct resource *res; 95562306a36Sopenharmony_ci int err = -ENOMEM, i, j, irq = -1; 95662306a36Sopenharmony_ci u32 reg; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci dd = devm_kzalloc(dev, sizeof(struct omap_des_dev), GFP_KERNEL); 95962306a36Sopenharmony_ci if (dd == NULL) { 96062306a36Sopenharmony_ci dev_err(dev, "unable to alloc data struct.\n"); 96162306a36Sopenharmony_ci goto err_data; 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci dd->dev = dev; 96462306a36Sopenharmony_ci platform_set_drvdata(pdev, dd); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci err = (dev->of_node) ? omap_des_get_of(dd, pdev) : 96762306a36Sopenharmony_ci omap_des_get_pdev(dd, pdev); 96862306a36Sopenharmony_ci if (err) 96962306a36Sopenharmony_ci goto err_res; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci dd->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 97262306a36Sopenharmony_ci if (IS_ERR(dd->io_base)) { 97362306a36Sopenharmony_ci err = PTR_ERR(dd->io_base); 97462306a36Sopenharmony_ci goto err_res; 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci dd->phys_base = res->start; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci pm_runtime_use_autosuspend(dev); 97962306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, DEFAULT_AUTOSUSPEND_DELAY); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci pm_runtime_enable(dev); 98262306a36Sopenharmony_ci err = pm_runtime_resume_and_get(dev); 98362306a36Sopenharmony_ci if (err < 0) { 98462306a36Sopenharmony_ci dev_err(dd->dev, "%s: failed to get_sync(%d)\n", __func__, err); 98562306a36Sopenharmony_ci goto err_get; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci omap_des_dma_stop(dd); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci reg = omap_des_read(dd, DES_REG_REV(dd)); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci pm_runtime_put_sync(dev); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci dev_info(dev, "OMAP DES hw accel rev: %u.%u\n", 99562306a36Sopenharmony_ci (reg & dd->pdata->major_mask) >> dd->pdata->major_shift, 99662306a36Sopenharmony_ci (reg & dd->pdata->minor_mask) >> dd->pdata->minor_shift); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci tasklet_init(&dd->done_task, omap_des_done_task, (unsigned long)dd); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci err = omap_des_dma_init(dd); 100162306a36Sopenharmony_ci if (err == -EPROBE_DEFER) { 100262306a36Sopenharmony_ci goto err_irq; 100362306a36Sopenharmony_ci } else if (err && DES_REG_IRQ_STATUS(dd) && DES_REG_IRQ_ENABLE(dd)) { 100462306a36Sopenharmony_ci dd->pio_only = 1; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 100762306a36Sopenharmony_ci if (irq < 0) { 100862306a36Sopenharmony_ci err = irq; 100962306a36Sopenharmony_ci goto err_irq; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci err = devm_request_irq(dev, irq, omap_des_irq, 0, 101362306a36Sopenharmony_ci dev_name(dev), dd); 101462306a36Sopenharmony_ci if (err) { 101562306a36Sopenharmony_ci dev_err(dev, "Unable to grab omap-des IRQ\n"); 101662306a36Sopenharmony_ci goto err_irq; 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci INIT_LIST_HEAD(&dd->list); 102262306a36Sopenharmony_ci spin_lock_bh(&list_lock); 102362306a36Sopenharmony_ci list_add_tail(&dd->list, &dev_list); 102462306a36Sopenharmony_ci spin_unlock_bh(&list_lock); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci /* Initialize des crypto engine */ 102762306a36Sopenharmony_ci dd->engine = crypto_engine_alloc_init(dev, 1); 102862306a36Sopenharmony_ci if (!dd->engine) { 102962306a36Sopenharmony_ci err = -ENOMEM; 103062306a36Sopenharmony_ci goto err_engine; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci err = crypto_engine_start(dd->engine); 103462306a36Sopenharmony_ci if (err) 103562306a36Sopenharmony_ci goto err_engine; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci for (i = 0; i < dd->pdata->algs_info_size; i++) { 103862306a36Sopenharmony_ci for (j = 0; j < dd->pdata->algs_info[i].size; j++) { 103962306a36Sopenharmony_ci algp = &dd->pdata->algs_info[i].algs_list[j]; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci pr_debug("reg alg: %s\n", algp->base.base.cra_name); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci err = crypto_engine_register_skcipher(algp); 104462306a36Sopenharmony_ci if (err) 104562306a36Sopenharmony_ci goto err_algs; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci dd->pdata->algs_info[i].registered++; 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci return 0; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_cierr_algs: 105462306a36Sopenharmony_ci for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) 105562306a36Sopenharmony_ci for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) 105662306a36Sopenharmony_ci crypto_engine_unregister_skcipher( 105762306a36Sopenharmony_ci &dd->pdata->algs_info[i].algs_list[j]); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_cierr_engine: 106062306a36Sopenharmony_ci if (dd->engine) 106162306a36Sopenharmony_ci crypto_engine_exit(dd->engine); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci omap_des_dma_cleanup(dd); 106462306a36Sopenharmony_cierr_irq: 106562306a36Sopenharmony_ci tasklet_kill(&dd->done_task); 106662306a36Sopenharmony_cierr_get: 106762306a36Sopenharmony_ci pm_runtime_disable(dev); 106862306a36Sopenharmony_cierr_res: 106962306a36Sopenharmony_ci dd = NULL; 107062306a36Sopenharmony_cierr_data: 107162306a36Sopenharmony_ci dev_err(dev, "initialization failed.\n"); 107262306a36Sopenharmony_ci return err; 107362306a36Sopenharmony_ci} 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_cistatic int omap_des_remove(struct platform_device *pdev) 107662306a36Sopenharmony_ci{ 107762306a36Sopenharmony_ci struct omap_des_dev *dd = platform_get_drvdata(pdev); 107862306a36Sopenharmony_ci int i, j; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci spin_lock_bh(&list_lock); 108162306a36Sopenharmony_ci list_del(&dd->list); 108262306a36Sopenharmony_ci spin_unlock_bh(&list_lock); 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) 108562306a36Sopenharmony_ci for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) 108662306a36Sopenharmony_ci crypto_engine_unregister_skcipher( 108762306a36Sopenharmony_ci &dd->pdata->algs_info[i].algs_list[j]); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci tasklet_kill(&dd->done_task); 109062306a36Sopenharmony_ci omap_des_dma_cleanup(dd); 109162306a36Sopenharmony_ci pm_runtime_disable(dd->dev); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci return 0; 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 109762306a36Sopenharmony_cistatic int omap_des_suspend(struct device *dev) 109862306a36Sopenharmony_ci{ 109962306a36Sopenharmony_ci pm_runtime_put_sync(dev); 110062306a36Sopenharmony_ci return 0; 110162306a36Sopenharmony_ci} 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_cistatic int omap_des_resume(struct device *dev) 110462306a36Sopenharmony_ci{ 110562306a36Sopenharmony_ci int err; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci err = pm_runtime_resume_and_get(dev); 110862306a36Sopenharmony_ci if (err < 0) { 110962306a36Sopenharmony_ci dev_err(dev, "%s: failed to get_sync(%d)\n", __func__, err); 111062306a36Sopenharmony_ci return err; 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci return 0; 111362306a36Sopenharmony_ci} 111462306a36Sopenharmony_ci#endif 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(omap_des_pm_ops, omap_des_suspend, omap_des_resume); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_cistatic struct platform_driver omap_des_driver = { 111962306a36Sopenharmony_ci .probe = omap_des_probe, 112062306a36Sopenharmony_ci .remove = omap_des_remove, 112162306a36Sopenharmony_ci .driver = { 112262306a36Sopenharmony_ci .name = "omap-des", 112362306a36Sopenharmony_ci .pm = &omap_des_pm_ops, 112462306a36Sopenharmony_ci .of_match_table = of_match_ptr(omap_des_of_match), 112562306a36Sopenharmony_ci }, 112662306a36Sopenharmony_ci}; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_cimodule_platform_driver(omap_des_driver); 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ciMODULE_DESCRIPTION("OMAP DES hw acceleration support."); 113162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 113262306a36Sopenharmony_ciMODULE_AUTHOR("Joel Fernandes <joelf@ti.com>"); 1133