diff --git a/drivers/virt/coco/host/Kconfig b/drivers/virt/coco/host/Kconfig
index c04b0446cd5f..f2b05b15a24e 100644
--- a/drivers/virt/coco/host/Kconfig
+++ b/drivers/virt/coco/host/Kconfig
@@ -7,3 +7,10 @@ config TSM
 
 config TDX_TSM_BUS
 	bool
+
+config TDX_TSM
+	depends on INTEL_TDX_HOST
+	select TDX_TSM_BUS
+	select PCI_TSM
+	select TSM
+	tristate "TDX TEE Security Manager Driver"
diff --git a/drivers/virt/coco/host/Makefile b/drivers/virt/coco/host/Makefile
index ce1ab15ac8d3..38ee9c96b921 100644
--- a/drivers/virt/coco/host/Makefile
+++ b/drivers/virt/coco/host/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_TSM) += tsm.o
 tsm-y := tsm-core.o
 
 obj-$(CONFIG_TDX_TSM_BUS) += tdx_tsm_bus.o
+obj-$(CONFIG_TDX_TSM) += tdx_tsm.o
diff --git a/drivers/virt/coco/host/tdx_tsm.c b/drivers/virt/coco/host/tdx_tsm.c
new file mode 100644
index 000000000000..72f3705fe7bb
--- /dev/null
+++ b/drivers/virt/coco/host/tdx_tsm.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2024 Intel Corporation. All rights reserved. */
+#include <linux/bitfield.h>
+#include <linux/pci.h>
+#include <linux/pci-tsm.h>
+#include <linux/tdx_tsm_bus.h>
+#include <linux/tsm.h>
+#include <asm/tdx.h>
+
+#define TDISP_FUNC_ID		GENMASK(15, 0)
+#define TDISP_FUNC_ID_SEGMENT		GENMASK(23, 16)
+#define TDISP_FUNC_ID_SEG_VALID		BIT(24)
+
+static inline u32 tdisp_func_id(struct pci_dev *pdev)
+{
+	u32 func_id;
+
+	func_id = FIELD_PREP(TDISP_FUNC_ID_SEGMENT, pci_domain_nr(pdev->bus));
+	if (func_id)
+		func_id |= TDISP_FUNC_ID_SEG_VALID;
+	func_id |= FIELD_PREP(TDISP_FUNC_ID,
+			      PCI_DEVID(pdev->bus->number, pdev->devfn));
+
+	return func_id;
+}
+
+struct tdx_tsm {
+	struct pci_tsm_pf0 pci;
+	u32 func_id;
+};
+
+static struct tdx_tsm *to_tdx_tsm(struct pci_tsm *tsm)
+{
+	return container_of(tsm, struct tdx_tsm, pci.tsm);
+}
+
+struct tdx_tdi {
+	struct pci_tdi tdi;
+	u32 func_id;
+};
+
+static struct tdx_tdi *to_tdx_tdi(struct pci_tdi *tdi)
+{
+	return container_of(tdi, struct tdx_tdi, tdi);
+}
+
+static struct pci_tdi *tdx_tsm_bind(struct pci_dev *pdev,
+				    struct pci_dev *dsm_dev,
+				    struct kvm *kvm, u64 tdi_id)
+{
+	struct tdx_tdi *ttdi __free(kfree) =
+		kzalloc(sizeof(*ttdi), GFP_KERNEL);
+	if (!ttdi)
+		return NULL;
+
+	ttdi->func_id = tdisp_func_id(pdev);
+	ttdi->tdi.pdev = pdev;
+	ttdi->tdi.dsm_dev = pci_dev_get(dsm_dev);
+	ttdi->tdi.kvm = kvm;
+
+	/*TODO: TDX Module required operations */
+
+	return &no_free_ptr(ttdi)->tdi;
+}
+
+static void tdx_tsm_unbind(struct pci_tdi *tdi)
+{
+	struct tdx_tdi *ttdi = to_tdx_tdi(tdi);
+
+	/*TODO: TDX Module required operations */
+
+	pci_dev_put(ttdi->tdi.dsm_dev);
+	kfree(ttdi);
+}
+
+static int tdx_tsm_guest_req(struct pci_dev *pdev,
+			     struct pci_tsm_guest_req_info *info)
+{
+	return -ENXIO;
+}
+
+static int tdx_tsm_connect(struct pci_dev *pdev)
+{
+	return -ENXIO;
+}
+
+static void tdx_tsm_disconnect(struct pci_dev *pdev)
+{
+}
+
+static struct pci_tsm *tdx_tsm_pci_probe(struct pci_dev *pdev)
+{
+	if (is_pci_tsm_pf0(pdev)) {
+		int rc;
+
+		struct tdx_tsm *ttsm __free(kfree) =
+			kzalloc(sizeof(*ttsm), GFP_KERNEL);
+		if (!ttsm)
+			return NULL;
+
+		rc = pci_tsm_pf0_initialize(pdev, &ttsm->pci);
+		if (rc)
+			return NULL;
+
+		ttsm->func_id = tdisp_func_id(pdev);
+
+		pci_info(pdev, "PF tsm enabled\n");
+		return &no_free_ptr(ttsm)->pci.tsm;
+	}
+
+	/* for VF and MFD */
+	struct pci_tsm *pci_tsm __free(kfree) =
+		kzalloc(sizeof(*pci_tsm), GFP_KERNEL);
+	if (!pci_tsm)
+		return NULL;
+
+	pci_tsm_initialize(pdev, pci_tsm);
+
+	pci_info(pdev, "VF/MFD tsm enabled\n");
+	return no_free_ptr(pci_tsm);
+}
+
+static void tdx_tsm_pci_remove(struct pci_tsm *tsm)
+{
+	if (is_pci_tsm_pf0(tsm->pdev)) {
+		struct tdx_tsm *ttsm = to_tdx_tsm(tsm);
+
+		pci_info(tsm->pdev, "PF tsm disabled\n");
+		kfree(ttsm);
+
+		return;
+	}
+
+	/* for VF and MFD */
+	kfree(tsm);
+}
+
+static const struct pci_tsm_ops tdx_pci_tsm_ops = {
+	.probe = tdx_tsm_pci_probe,
+	.remove = tdx_tsm_pci_remove,
+	.connect = tdx_tsm_connect,
+	.disconnect = tdx_tsm_disconnect,
+	.bind = tdx_tsm_bind,
+	.unbind = tdx_tsm_unbind,
+	.guest_req = tdx_tsm_guest_req,
+};
+
+static void unregister_tsm(void *tsm_core)
+{
+	tsm_unregister(tsm_core);
+}
+
+static int tdx_tsm_probe(struct device *dev)
+{
+	struct tsm_core_dev *tsm_core;
+
+	tsm_core = tsm_register(dev, NULL, &tdx_pci_tsm_ops);
+	if (IS_ERR(tsm_core)) {
+		dev_err(dev, "failed to register TSM: (%pe)\n", tsm_core);
+		return PTR_ERR(tsm_core);
+	}
+
+	return devm_add_action_or_reset(dev, unregister_tsm, tsm_core);
+}
+
+static struct device_driver tdx_tsm_driver = {
+	.probe = tdx_tsm_probe,
+	.bus = &tdx_subsys,
+	.owner = THIS_MODULE,
+	.name = KBUILD_MODNAME,
+	.mod_name = KBUILD_MODNAME,
+};
+
+static int __init tdx_tsm_init(void)
+{
+	return driver_register(&tdx_tsm_driver);
+}
+module_init(tdx_tsm_init);
+
+static void __exit tdx_tsm_exit(void)
+{
+	driver_unregister(&tdx_tsm_driver);
+}
+module_exit(tdx_tsm_exit);
+
+MODULE_IMPORT_NS("TDX");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("tdx_tsm");
+MODULE_DESCRIPTION("TDX TEE Security Manager");
