|
@@ -40,6 +40,8 @@
|
|
|
#define DST_MAXBURST 4
|
|
|
#define DMA_MIN (DST_MAXBURST * sizeof(u32))
|
|
|
|
|
|
+#define _calc_walked(inout) (dd->inout##_walk.offset - dd->inout##_sg->offset)
|
|
|
+
|
|
|
/* OMAP TRM gives bitfields as start:end, where start is the higher bit
|
|
|
number. For example 7:0 */
|
|
|
#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
|
|
@@ -92,6 +94,8 @@
|
|
|
#define FLAGS_FAST BIT(5)
|
|
|
#define FLAGS_BUSY BIT(6)
|
|
|
|
|
|
+#define AES_BLOCK_WORDS (AES_BLOCK_SIZE >> 2)
|
|
|
+
|
|
|
struct omap_aes_ctx {
|
|
|
struct omap_aes_dev *dd;
|
|
|
|
|
@@ -157,6 +161,8 @@ struct omap_aes_dev {
|
|
|
size_t total;
|
|
|
struct scatterlist *in_sg;
|
|
|
struct scatterlist *out_sg;
|
|
|
+ struct scatter_walk in_walk;
|
|
|
+ struct scatter_walk out_walk;
|
|
|
int dma_in;
|
|
|
struct dma_chan *dma_lch_in;
|
|
|
int dma_out;
|
|
@@ -863,6 +869,90 @@ static const struct omap_aes_pdata omap_aes_pdata_omap4 = {
|
|
|
.minor_shift = 0,
|
|
|
};
|
|
|
|
|
|
+static irqreturn_t omap_aes_irq(int irq, void *dev_id)
|
|
|
+{
|
|
|
+ struct omap_aes_dev *dd = dev_id;
|
|
|
+ u32 status, i;
|
|
|
+ u32 *src, *dst;
|
|
|
+
|
|
|
+ status = omap_aes_read(dd, AES_REG_IRQ_STATUS(dd));
|
|
|
+ if (status & AES_REG_IRQ_DATA_IN) {
|
|
|
+ omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x0);
|
|
|
+
|
|
|
+ BUG_ON(!dd->in_sg);
|
|
|
+
|
|
|
+ BUG_ON(_calc_walked(in) > dd->in_sg->length);
|
|
|
+
|
|
|
+ src = sg_virt(dd->in_sg) + _calc_walked(in);
|
|
|
+
|
|
|
+ for (i = 0; i < AES_BLOCK_WORDS; i++) {
|
|
|
+ omap_aes_write(dd, AES_REG_DATA_N(dd, i), *src);
|
|
|
+
|
|
|
+ scatterwalk_advance(&dd->in_walk, 4);
|
|
|
+ if (dd->in_sg->length == _calc_walked(in)) {
|
|
|
+ dd->in_sg = scatterwalk_sg_next(dd->in_sg);
|
|
|
+ if (dd->in_sg) {
|
|
|
+ scatterwalk_start(&dd->in_walk,
|
|
|
+ dd->in_sg);
|
|
|
+ src = sg_virt(dd->in_sg) +
|
|
|
+ _calc_walked(in);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ src++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Clear IRQ status */
|
|
|
+ status &= ~AES_REG_IRQ_DATA_IN;
|
|
|
+ omap_aes_write(dd, AES_REG_IRQ_STATUS(dd), status);
|
|
|
+
|
|
|
+ /* Enable DATA_OUT interrupt */
|
|
|
+ omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x4);
|
|
|
+
|
|
|
+ } else if (status & AES_REG_IRQ_DATA_OUT) {
|
|
|
+ omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x0);
|
|
|
+
|
|
|
+ BUG_ON(!dd->out_sg);
|
|
|
+
|
|
|
+ BUG_ON(_calc_walked(out) > dd->out_sg->length);
|
|
|
+
|
|
|
+ dst = sg_virt(dd->out_sg) + _calc_walked(out);
|
|
|
+
|
|
|
+ for (i = 0; i < AES_BLOCK_WORDS; i++) {
|
|
|
+ *dst = omap_aes_read(dd, AES_REG_DATA_N(dd, i));
|
|
|
+ scatterwalk_advance(&dd->out_walk, 4);
|
|
|
+ if (dd->out_sg->length == _calc_walked(out)) {
|
|
|
+ dd->out_sg = scatterwalk_sg_next(dd->out_sg);
|
|
|
+ if (dd->out_sg) {
|
|
|
+ scatterwalk_start(&dd->out_walk,
|
|
|
+ dd->out_sg);
|
|
|
+ dst = sg_virt(dd->out_sg) +
|
|
|
+ _calc_walked(out);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ dst++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ dd->total -= AES_BLOCK_SIZE;
|
|
|
+
|
|
|
+ BUG_ON(dd->total < 0);
|
|
|
+
|
|
|
+ /* Clear IRQ status */
|
|
|
+ status &= ~AES_REG_IRQ_DATA_OUT;
|
|
|
+ omap_aes_write(dd, AES_REG_IRQ_STATUS(dd), status);
|
|
|
+
|
|
|
+ if (!dd->total)
|
|
|
+ /* All bytes read! */
|
|
|
+ tasklet_schedule(&dd->done_task);
|
|
|
+ else
|
|
|
+ /* Enable DATA_IN interrupt for next block */
|
|
|
+ omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x2);
|
|
|
+ }
|
|
|
+
|
|
|
+ return IRQ_HANDLED;
|
|
|
+}
|
|
|
+
|
|
|
static const struct of_device_id omap_aes_of_match[] = {
|
|
|
{
|
|
|
.compatible = "ti,omap2-aes",
|