#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))
 #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;
 
        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;
        .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",