#define CONTEXT_CONTROL_IV3                    BIT(8)
 #define CONTEXT_CONTROL_DIGEST_CNT             BIT(9)
 #define CONTEXT_CONTROL_COUNTER_MODE           BIT(10)
+#define CONTEXT_CONTROL_CRYPTO_STORE           BIT(12)
 #define CONTEXT_CONTROL_HASH_STORE             BIT(19)
 
 /* The hash counter given to the engine in the context has a granularity of
 
 #define EIP197_TOKEN_HASH_RESULT_VERIFY                BIT(16)
 
+#define EIP197_TOKEN_CTX_OFFSET(x)             (x)
+#define EIP197_TOKEN_DIRECTION_EXTERNAL                BIT(11)
+#define EIP197_TOKEN_EXEC_IF_SUCCESSFUL                (0x1 << 12)
+
 #define EIP197_TOKEN_STAT_LAST_HASH            BIT(0)
 #define EIP197_TOKEN_STAT_LAST_PACKET          BIT(1)
 #define EIP197_TOKEN_OPCODE_DIRECTION          0x0
 #define EIP197_TOKEN_OPCODE_NOOP               EIP197_TOKEN_OPCODE_INSERT
 #define EIP197_TOKEN_OPCODE_RETRIEVE           0x4
 #define EIP197_TOKEN_OPCODE_VERIFY             0xd
+#define EIP197_TOKEN_OPCODE_CTX_ACCESS         0xe
 #define EIP197_TOKEN_OPCODE_BYPASS             GENMASK(3, 0)
 
 static inline void eip197_noop_token(struct safexcel_token *token)
 
 /* Instructions */
 #define EIP197_TOKEN_INS_INSERT_HASH_DIGEST    0x1c
+#define EIP197_TOKEN_INS_ORIGIN_IV0            0x14
+#define EIP197_TOKEN_INS_ORIGIN_LEN(x)         ((x) << 5)
 #define EIP197_TOKEN_INS_TYPE_OUTPUT           BIT(5)
 #define EIP197_TOKEN_INS_TYPE_HASH             BIT(6)
 #define EIP197_TOKEN_INS_TYPE_CRYTO            BIT(7)
 
                                    u32 length)
 {
        struct safexcel_token *token;
-       unsigned offset = 0;
+       u32 offset = 0, block_sz = 0;
 
        if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) {
                switch (ctx->alg) {
                case SAFEXCEL_DES:
-                       offset = DES_BLOCK_SIZE / sizeof(u32);
-                       memcpy(cdesc->control_data.token, iv, DES_BLOCK_SIZE);
+                       block_sz = DES_BLOCK_SIZE;
                        cdesc->control_data.options |= EIP197_OPTION_2_TOKEN_IV_CMD;
                        break;
                case SAFEXCEL_3DES:
-                       offset = DES3_EDE_BLOCK_SIZE / sizeof(u32);
-                       memcpy(cdesc->control_data.token, iv, DES3_EDE_BLOCK_SIZE);
+                       block_sz = DES3_EDE_BLOCK_SIZE;
                        cdesc->control_data.options |= EIP197_OPTION_2_TOKEN_IV_CMD;
                        break;
                case SAFEXCEL_AES:
-                       offset = AES_BLOCK_SIZE / sizeof(u32);
-                       memcpy(cdesc->control_data.token, iv, AES_BLOCK_SIZE);
+                       block_sz = AES_BLOCK_SIZE;
                        cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD;
                        break;
                }
+
+               offset = block_sz / sizeof(u32);
+               memcpy(cdesc->control_data.token, iv, block_sz);
        }
 
        token = (struct safexcel_token *)(cdesc->control_data.token + offset);
        token[0].instructions = EIP197_TOKEN_INS_LAST |
                                EIP197_TOKEN_INS_TYPE_CRYTO |
                                EIP197_TOKEN_INS_TYPE_OUTPUT;
+
+       if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) {
+               u32 last = (EIP197_MAX_TOKENS - 1) - offset;
+
+               token[last].opcode = EIP197_TOKEN_OPCODE_CTX_ACCESS;
+               token[last].packet_length = EIP197_TOKEN_DIRECTION_EXTERNAL |
+                                           EIP197_TOKEN_EXEC_IF_SUCCESSFUL|
+                                           EIP197_TOKEN_CTX_OFFSET(0x2);
+               token[last].stat = EIP197_TOKEN_STAT_LAST_HASH |
+                       EIP197_TOKEN_STAT_LAST_PACKET;
+               token[last].instructions =
+                       EIP197_TOKEN_INS_ORIGIN_LEN(block_sz / sizeof(u32)) |
+                       EIP197_TOKEN_INS_ORIGIN_IV0;
+
+               /* Store the updated IV values back in the internal context
+                * registers.
+                */
+               cdesc->control_data.control1 |= CONTEXT_CONTROL_CRYPTO_STORE;
+       }
 }
 
 static void safexcel_aead_token(struct safexcel_cipher_ctx *ctx, u8 *iv,
 {
        struct skcipher_request *req = skcipher_request_cast(async);
        struct safexcel_cipher_req *sreq = skcipher_request_ctx(req);
+       struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(async->tfm);
        int err;
 
        if (sreq->needs_inv) {
                err = safexcel_handle_req_result(priv, ring, async, req->src,
                                                 req->dst, req->cryptlen, sreq,
                                                 should_complete, ret);
+
+               if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) {
+                       u32 block_sz = 0;
+
+                       switch (ctx->alg) {
+                       case SAFEXCEL_DES:
+                               block_sz = DES_BLOCK_SIZE;
+                               break;
+                       case SAFEXCEL_3DES:
+                               block_sz = DES3_EDE_BLOCK_SIZE;
+                               break;
+                       case SAFEXCEL_AES:
+                               block_sz = AES_BLOCK_SIZE;
+                               break;
+                       }
+
+                       memcpy(req->iv, ctx->base.ctxr->data, block_sz);
+               }
        }
 
        return err;