diff --git a/backends/tpm.c b/backends/tpm.c
index 4efe367..9b0d0a5 100644
--- a/backends/tpm.c
+++ b/backends/tpm.c
@@ -96,6 +96,20 @@ bool tpm_backend_get_tpm_established_flag(TPMBackend *s)
     return k->ops->get_tpm_established_flag(s);
 }
 
+int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty)
+{
+    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+    return k->ops->reset_tpm_established_flag(s, locty);
+}
+
+TPMVersion tpm_backend_get_tpm_version(TPMBackend *s)
+{
+    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+    return k->ops->get_tpm_version(s);
+}
+
 static bool tpm_backend_prop_get_opened(Object *obj, Error **errp)
 {
     TPMBackend *s = TPM_BACKEND(obj);
diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h
index 2b35fe2..9866c79 100644
--- a/hw/tpm/tpm_int.h
+++ b/hw/tpm/tpm_int.h
@@ -29,6 +29,7 @@ struct TPMState {
 
     char *backend;
     TPMBackend *be_driver;
+    TPMVersion be_tpm_version;
 };
 
 #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index 73ca906..f1361d2 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -267,6 +267,13 @@ static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
     return false;
 }
 
+static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb,
+                                                      uint8_t locty)
+{
+    /* only a TPM 2.0 will support this */
+    return 0;
+}
+
 static bool tpm_passthrough_get_startup_error(TPMBackend *tb)
 {
     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
@@ -324,6 +331,11 @@ static const char *tpm_passthrough_create_desc(void)
     return "Passthrough TPM backend driver";
 }
 
+static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb)
+{
+    return TPM_VERSION_1_2;
+}
+
 /*
  * A basic test of a TPM device. We expect a well formatted response header
  * (error response is fine) within one second.
@@ -540,6 +552,8 @@ static const TPMDriverOps tpm_passthrough_driver = {
     .deliver_request          = tpm_passthrough_deliver_request,
     .cancel_cmd               = tpm_passthrough_cancel_cmd,
     .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag,
+    .reset_tpm_established_flag = tpm_passthrough_reset_tpm_established_flag,
+    .get_tpm_version          = tpm_passthrough_get_tpm_version,
 };
 
 static void tpm_passthrough_inst_init(Object *obj)
diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
index b8235d5..636e6d3 100644
--- a/hw/tpm/tpm_tis.c
+++ b/hw/tpm/tpm_tis.c
@@ -17,6 +17,9 @@
  * supports version 1.3, 21 March 2013
  * In the developers menu choose the PC Client section then find the TIS
  * specification.
+ *
+ * TPM TIS for TPM 2 implementation following TCG PC Client Platform
+ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43
  */
 
 #include "sysemu/tpm_backend.h"
@@ -49,6 +52,7 @@
 #define TPM_TIS_REG_INTF_CAPABILITY       0x14
 #define TPM_TIS_REG_STS                   0x18
 #define TPM_TIS_REG_DATA_FIFO             0x24
+#define TPM_TIS_REG_INTERFACE_ID          0x30
 #define TPM_TIS_REG_DATA_XFIFO            0x80
 #define TPM_TIS_REG_DATA_XFIFO_END        0xbc
 #define TPM_TIS_REG_DID_VID               0xf00
@@ -57,6 +61,12 @@
 /* vendor-specific registers */
 #define TPM_TIS_REG_DEBUG                 0xf90
 
+#define TPM_TIS_STS_TPM_FAMILY_MASK         (0x3 << 26)/* TPM 2.0 */
+#define TPM_TIS_STS_TPM_FAMILY1_2           (0 << 26)  /* TPM 2.0 */
+#define TPM_TIS_STS_TPM_FAMILY2_0           (1 << 26)  /* TPM 2.0 */
+#define TPM_TIS_STS_RESET_ESTABLISHMENT_BIT (1 << 25)  /* TPM 2.0 */
+#define TPM_TIS_STS_COMMAND_CANCEL          (1 << 24)  /* TPM 2.0 */
+
 #define TPM_TIS_STS_VALID                 (1 << 7)
 #define TPM_TIS_STS_COMMAND_READY         (1 << 6)
 #define TPM_TIS_STS_TPM_GO                (1 << 5)
@@ -102,15 +112,42 @@
 #endif
 
 #define TPM_TIS_CAP_INTERFACE_VERSION1_3 (2 << 28)
+#define TPM_TIS_CAP_INTERFACE_VERSION1_3_FOR_TPM2_0 (3 << 28)
 #define TPM_TIS_CAP_DATA_TRANSFER_64B    (3 << 9)
 #define TPM_TIS_CAP_DATA_TRANSFER_LEGACY (0 << 9)
 #define TPM_TIS_CAP_BURST_COUNT_DYNAMIC  (0 << 8)
 #define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL  (1 << 4) /* support is mandatory */
-#define TPM_TIS_CAPABILITIES_SUPPORTED   (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
-                                          TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
-                                          TPM_TIS_CAP_DATA_TRANSFER_64B | \
-                                          TPM_TIS_CAP_INTERFACE_VERSION1_3 | \
-                                          TPM_TIS_INTERRUPTS_SUPPORTED)
+#define TPM_TIS_CAPABILITIES_SUPPORTED1_3 \
+    (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
+     TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
+     TPM_TIS_CAP_DATA_TRANSFER_64B | \
+     TPM_TIS_CAP_INTERFACE_VERSION1_3 | \
+     TPM_TIS_INTERRUPTS_SUPPORTED)
+
+#define TPM_TIS_CAPABILITIES_SUPPORTED2_0 \
+    (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
+     TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
+     TPM_TIS_CAP_DATA_TRANSFER_64B | \
+     TPM_TIS_CAP_INTERFACE_VERSION1_3_FOR_TPM2_0 | \
+     TPM_TIS_INTERRUPTS_SUPPORTED)
+
+#define TPM_TIS_IFACE_ID_INTERFACE_TIS1_3   (0xf)     /* TPM 2.0 */
+#define TPM_TIS_IFACE_ID_INTERFACE_FIFO     (0x0)     /* TPM 2.0 */
+#define TPM_TIS_IFACE_ID_INTERFACE_VER_FIFO (0 << 4)  /* TPM 2.0 */
+#define TPM_TIS_IFACE_ID_CAP_5_LOCALITIES   (1 << 8)  /* TPM 2.0 */
+#define TPM_TIS_IFACE_ID_CAP_TIS_SUPPORTED  (1 << 13) /* TPM 2.0 */
+#define TPM_TIS_IFACE_ID_INT_SEL_LOCK       (1 << 19) /* TPM 2.0 */
+
+#define TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3 \
+    (TPM_TIS_IFACE_ID_INTERFACE_TIS1_3 | \
+     (~0 << 4)/* all of it is don't care */)
+
+/* if backend was a TPM 2.0: */
+#define TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0 \
+    (TPM_TIS_IFACE_ID_INTERFACE_FIFO | \
+     TPM_TIS_IFACE_ID_INTERFACE_VER_FIFO | \
+     TPM_TIS_IFACE_ID_CAP_5_LOCALITIES | \
+     TPM_TIS_IFACE_ID_CAP_TIS_SUPPORTED)
 
 #define TPM_TIS_TPM_DID       0x0001
 #define TPM_TIS_TPM_VID       PCI_VENDOR_ID_IBM
@@ -154,7 +191,8 @@ static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
 
 /*
  * Set the given flags in the STS register by clearing the register but
- * preserving the SELFTEST_DONE flag and then setting the new flags.
+ * preserving the SELFTEST_DONE and TPM_FAMILY_MASK flags and then setting
+ * the new flags.
  *
  * The SELFTEST_DONE flag is acquired from the backend that determines it by
  * peeking into TPM commands.
@@ -166,7 +204,7 @@ static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
  */
 static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags)
 {
-    l->sts &= TPM_TIS_STS_SELFTEST_DONE;
+    l->sts &= TPM_TIS_STS_SELFTEST_DONE | TPM_TIS_STS_TPM_FAMILY_MASK;
     l->sts |= flags;
 }
 
@@ -489,7 +527,17 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
         val = tis->loc[locty].ints;
         break;
     case TPM_TIS_REG_INTF_CAPABILITY:
-        val = TPM_TIS_CAPABILITIES_SUPPORTED;
+        switch (s->be_tpm_version) {
+        case TPM_VERSION_UNSPEC:
+            val = 0;
+            break;
+        case TPM_VERSION_1_2:
+            val = TPM_TIS_CAPABILITIES_SUPPORTED1_3;
+            break;
+        case TPM_VERSION_2_0:
+            val = TPM_TIS_CAPABILITIES_SUPPORTED2_0;
+            break;
+        }
         break;
     case TPM_TIS_REG_STS:
         if (tis->active_locty == locty) {
@@ -536,6 +584,9 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
             shift = 0; /* no more adjustments */
         }
         break;
+    case TPM_TIS_REG_INTERFACE_ID:
+        val = tis->loc[locty].iface_id;
+        break;
     case TPM_TIS_REG_DID_VID:
         val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
         break;
@@ -736,6 +787,25 @@ static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
             break;
         }
 
+        if (s->be_tpm_version == TPM_VERSION_2_0) {
+            /* some flags that are only supported for TPM 2 */
+            if (val & TPM_TIS_STS_COMMAND_CANCEL) {
+                if (tis->loc[locty].state == TPM_TIS_STATE_EXECUTION) {
+                    /*
+                     * request the backend to cancel. Some backends may not
+                     * support it
+                     */
+                    tpm_backend_cancel_cmd(s->be_driver);
+                }
+            }
+
+            if (val & TPM_TIS_STS_RESET_ESTABLISHMENT_BIT) {
+                if (locty == 3 || locty == 4) {
+                    tpm_backend_reset_tpm_established_flag(s->be_driver, locty);
+                }
+            }
+        }
+
         val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
                 TPM_TIS_STS_RESPONSE_RETRY);
 
@@ -860,6 +930,14 @@ static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
             }
         }
         break;
+        case TPM_TIS_REG_INTERFACE_ID:
+            if (val & TPM_TIS_IFACE_ID_INT_SEL_LOCK) {
+                for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
+                    tis->loc[l].iface_id |= TPM_TIS_IFACE_ID_INT_SEL_LOCK;
+                }
+            }
+
+        break;
     }
 }
 
@@ -894,6 +972,8 @@ static void tpm_tis_reset(DeviceState *dev)
     TPMTISEmuState *tis = &s->s.tis;
     int c;
 
+    s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
+
     tpm_backend_reset(s->be_driver);
 
     tis->active_locty = TPM_TIS_NO_LOCALITY;
@@ -902,7 +982,18 @@ static void tpm_tis_reset(DeviceState *dev)
 
     for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
         tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
-        tis->loc[c].sts = 0;
+        switch (s->be_tpm_version) {
+        case TPM_VERSION_UNSPEC:
+            break;
+        case TPM_VERSION_1_2:
+            tis->loc[c].sts = TPM_TIS_STS_TPM_FAMILY1_2;
+            tis->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3;
+            break;
+        case TPM_VERSION_2_0:
+            tis->loc[c].sts = TPM_TIS_STS_TPM_FAMILY2_0;
+            tis->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0;
+            break;
+        }
         tis->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
         tis->loc[c].ints = 0;
         tis->loc[c].state = TPM_TIS_STATE_IDLE;
diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h
index db78d51..a1df41f 100644
--- a/hw/tpm/tpm_tis.h
+++ b/hw/tpm/tpm_tis.h
@@ -42,6 +42,7 @@ typedef struct TPMLocality {
     TPMTISState state;
     uint8_t access;
     uint32_t sts;
+    uint32_t iface_id;
     uint32_t inte;
     uint32_t ints;
 
diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h
index 9b81ce9..848df41 100644
--- a/include/sysemu/tpm.h
+++ b/include/sysemu/tpm.h
@@ -20,6 +20,12 @@ int tpm_config_parse(QemuOptsList *opts_list, const char *optarg);
 int tpm_init(void);
 void tpm_cleanup(void);
 
+typedef enum  TPMVersion {
+    TPM_VERSION_UNSPEC = 0,
+    TPM_VERSION_1_2 = 1,
+    TPM_VERSION_2_0 = 2,
+} TPMVersion;
+
 #define TYPE_TPM_TIS                "tpm-tis"
 
 static inline bool tpm_find(void)
diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h
index 540ee25..0a366be 100644
--- a/include/sysemu/tpm_backend.h
+++ b/include/sysemu/tpm_backend.h
@@ -88,6 +88,10 @@ struct TPMDriverOps {
     void (*cancel_cmd)(TPMBackend *t);
 
     bool (*get_tpm_established_flag)(TPMBackend *t);
+
+    int (*reset_tpm_established_flag)(TPMBackend *t, uint8_t locty);
+
+    TPMVersion (*get_tpm_version)(TPMBackend *t);
 };
 
 
@@ -192,6 +196,15 @@ void tpm_backend_cancel_cmd(TPMBackend *s);
 bool tpm_backend_get_tpm_established_flag(TPMBackend *s);
 
 /**
+ * tpm_backend_reset_tpm_established_flag:
+ * @s: the backend
+ * @locty: the locality number
+ *
+ * Reset the TPM establishment flag.
+ */
+int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty);
+
+/**
  * tpm_backend_open:
  * @s: the backend to open
  * @errp: a pointer to return the #Error object if an error occurs.
@@ -201,6 +214,16 @@ bool tpm_backend_get_tpm_established_flag(TPMBackend *s);
  */
 void tpm_backend_open(TPMBackend *s, Error **errp);
 
+/**
+ * tpm_backend_get_tpm_version:
+ * @s: the backend to call into
+ *
+ * Get the TPM Version that is emulated at the backend.
+ *
+ * Returns TPMVersion.
+ */
+TPMVersion tpm_backend_get_tpm_version(TPMBackend *s);
+
 TPMBackend *qemu_find_tpm(const char *id);
 
 const TPMDriverOps *tpm_get_backend_driver(const char *type);
