diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst
index 54a696d961a7..596e5f15f459 100644
--- a/Documentation/gpu/drm-mm.rst
+++ b/Documentation/gpu/drm-mm.rst
@@ -380,6 +380,18 @@ GEM CMA Helper Functions Reference
 .. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c
    :export:
 
+GEM TTM Helper Functions Reference
+----------------------------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_gem_ttm_helper.c
+   :doc: overview
+
+.. kernel-doc:: include/drm/drm_gem_ttm_helper.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/drm_gem_ttm_helper.c
+   :export:
+
 VMA Offset Manager
 ==================
 
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index bcbc4234893a..684bd327eb07 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -160,6 +160,12 @@ config DRM_TTM
 	  GPU memory types. Will be enabled automatically if a device driver
 	  uses it.
 
+config DRM_TTM_HELPER
+	tristate
+	depends on DRM && DRM_TTM
+	help
+	  Helpers for TTM-based memory management
+
 config DRM_GEM_CMA_HELPER
 	bool
 	depends on DRM
@@ -179,6 +185,13 @@ config DRM_GEM_SHMEM_HELPER
 	help
 	  Choose this if you need the GEM shmem helper functions
 
+config DRM_GEM_TTM_HELPER
+	bool
+	depends on DRM
+	select DRM_TTM_HELPER
+	help
+	  Choose this if you need the GEM TTM helper functions
+
 config DRM_VM
 	bool
 	depends on DRM && MMU
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index d97c0a3a8cfc..acd0f3e4f079 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -33,6 +33,10 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
 drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
 drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
 
+drm_ttm_helper-y := drm_ttm_helper_common.o
+drm_ttm_helper-$(CONFIG_DRM_GEM_TTM_HELPER) += drm_gem_ttm_helper.o
+obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o
+
 drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper.o \
 		drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
 		drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
diff --git a/drivers/gpu/drm/drm_gem_ttm_helper.c b/drivers/gpu/drm/drm_gem_ttm_helper.c
new file mode 100644
index 000000000000..d52d3c439917
--- /dev/null
+++ b/drivers/gpu/drm/drm_gem_ttm_helper.c
@@ -0,0 +1,367 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <drm/drm_gem_ttm_helper.h>
+#include <drm/ttm/ttm_page_alloc.h>
+
+/**
+ * DOC: overview
+ *
+ * This library provides a GEM object that is backed by TTM-managed
+ * memory. It can be used for simple framebuffer devices with dedicated
+ * memory.
+ */
+
+/*
+ * Buffer-objects helpers
+ */
+
+static void drm_gem_ttm_cleanup(struct drm_gem_ttm_object *gbo)
+{
+	/* We got here via ttm_bo_put(), which means that the
+	 * TTM buffer object in 'bo' has already been cleaned
+	 * up; only release the GEM object. */
+	drm_gem_object_release(&gbo->gem);
+}
+
+static void drm_gem_ttm_destroy(struct drm_gem_ttm_object *gbo)
+{
+	drm_gem_ttm_cleanup(gbo);
+	kfree(gbo);
+}
+
+static void ttm_buffer_object_destroy(struct ttm_buffer_object *bo)
+{
+	struct drm_gem_ttm_object *gbo = drm_gem_ttm_of_bo(bo);
+	drm_gem_ttm_destroy(gbo);
+}
+
+static void drm_gem_ttm_placement(struct drm_gem_ttm_object *gbo, int pl_flag)
+{
+	unsigned int i;
+	unsigned int c = 0;
+
+	gbo->placement.placement = gbo->placements;
+	gbo->placement.busy_placement = gbo->placements;
+
+	if (pl_flag & TTM_PL_FLAG_VRAM)
+		gbo->placements[c++].flags = TTM_PL_FLAG_WC |
+					     TTM_PL_FLAG_UNCACHED |
+					     TTM_PL_FLAG_VRAM;
+
+	if (pl_flag & TTM_PL_FLAG_SYSTEM)
+		gbo->placements[c++].flags = TTM_PL_MASK_CACHING |
+					     TTM_PL_FLAG_SYSTEM;
+
+	if (!c)
+		gbo->placements[c++].flags = TTM_PL_MASK_CACHING |
+					     TTM_PL_FLAG_SYSTEM;
+
+	gbo->placement.num_placement = c;
+	gbo->placement.num_busy_placement = c;
+
+	for (i = 0; i < c; ++i) {
+		gbo->placements[i].fpfn = 0;
+		gbo->placements[i].lpfn = 0;
+	}
+}
+
+static int drm_gem_ttm_init(struct drm_device *dev,
+			    struct ttm_bo_device *bdev,
+			    struct drm_gem_ttm_object *gbo,
+			    unsigned long size, uint32_t pg_align,
+			    bool interruptible)
+{
+	int ret;
+	size_t acc_size;
+
+	ret = drm_gem_object_init(dev, &gbo->gem, size);
+	if (ret)
+		return ret;
+
+	acc_size = ttm_bo_dma_acc_size(bdev, size, sizeof(*gbo));
+
+	gbo->bo.bdev = bdev;
+	drm_gem_ttm_placement(gbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
+
+	ret = ttm_bo_init(bdev, &gbo->bo, size, ttm_bo_type_device,
+			  &gbo->placement, pg_align, interruptible, acc_size,
+			  NULL, NULL, ttm_buffer_object_destroy);
+	if (ret)
+		goto err_drm_gem_object_release;
+
+	return 0;
+
+err_drm_gem_object_release:
+	drm_gem_object_release(&gbo->gem);
+	return ret;
+}
+
+/**
+ * drm_gem_ttm_create() - Creates a TTM-backed GEM object
+ * @dev:		the DRM device
+ * @bdev:		the TTM BO device backing the object
+ * @size:		the buffer size in bytes
+ * @pg_align:		the buffer's alignment in multiples of the page size
+ * @interruptible:	sleep interruptible if waiting for memory
+ *
+ * Returns:
+ * A new instance of struct_gem_ttm_object on success, or
+ * an ERR_PTR-encoded error code otherwise.
+ */
+struct drm_gem_ttm_object* drm_gem_ttm_create(struct drm_device *dev,
+					      struct ttm_bo_device *bdev,
+					      unsigned long size,
+					      uint32_t pg_align,
+					      bool interruptible)
+{
+	struct drm_gem_ttm_object *gbo;
+	int ret;
+
+	gbo = kzalloc(sizeof(*gbo), GFP_KERNEL);
+	if (!gbo)
+		return ERR_PTR(-ENOMEM);
+
+	ret = drm_gem_ttm_init(dev, bdev, gbo, size, pg_align, interruptible);
+	if (ret < 0)
+		goto err_kfree;
+
+	return gbo;
+
+err_kfree:
+	kfree(gbo);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(drm_gem_ttm_create);
+
+/**
+ * drm_gem_ttm_put() - Releases a reference to a TTM-backed GEM object
+ * @gbo:	the GEM-TTM object
+ *
+ * See ttm_bo_put() for more information.
+ */
+void drm_gem_ttm_put(struct drm_gem_ttm_object *gbo)
+{
+	ttm_bo_put(&gbo->bo);
+}
+EXPORT_SYMBOL(drm_gem_ttm_put);
+
+/**
+ * drm_gem_ttm_reserve() - Reserves a TTM-backed GEM object
+ * @gbo:	the GEM-TTM object
+ * @no_wait:	don't wait for buffer object to become available
+ *
+ * See ttm_bo_reserve() for more information.
+ *
+ * Returns:
+ * 0 on success, or
+ * a negative error code otherwise
+ */
+int drm_gem_ttm_reserve(struct drm_gem_ttm_object *gbo, bool no_wait)
+{
+	return ttm_bo_reserve(&gbo->bo, true, no_wait, NULL);
+}
+EXPORT_SYMBOL(drm_gem_ttm_reserve);
+
+/**
+ * drm_gem_ttm_unreserve() - Release a reservation acquired by drm_gem_ttm_reserve
+ * @gbo:	the GEM TTM object
+ *
+ * See ttm_bo_unreserve() for more information.
+ */
+void drm_gem_ttm_unreserve(struct drm_gem_ttm_object *gbo)
+{
+	ttm_bo_unreserve(&gbo->bo);
+}
+EXPORT_SYMBOL(drm_gem_ttm_unreserve);
+
+/**
+ * drm_gem_ttm_mmap_offset() - Returns a GEM TTM object's mmap offset
+ * @gbo:	the GEM TTM object
+ *
+ * See drm_vma_node_offset_addr() for more information.
+ *
+ * Returns:
+ * The buffer object's offset for userspace mappings on success, or
+ * 0 if no offset is allocated.
+ */
+u64 drm_gem_ttm_mmap_offset(struct drm_gem_ttm_object *gbo)
+{
+	return drm_vma_node_offset_addr(&gbo->bo.vma_node);
+}
+EXPORT_SYMBOL(drm_gem_ttm_mmap_offset);
+
+/**
+ * drm_gem_ttm_vram_offset() - Returns a GEM-TTM object's offset in video memory
+ * @gbo:	the GEM TTM object
+ *
+ * This function returns the buffer object's offset in the device's video
+ * memory. The buffer object has to be pinned to TT_PL_VRAM.
+ *
+ * Returns:
+ * The buffer object's offset in video memory on success, or
+ * a negative error code otherwise.
+ */
+s64 drm_gem_ttm_vram_offset(struct drm_gem_ttm_object *gbo)
+{
+	if (!gbo->pin_count)
+		return (s64)-ENODEV;
+	return gbo->bo.offset;
+}
+EXPORT_SYMBOL(drm_gem_ttm_vram_offset);
+
+/**
+ * drm_gem_ttm_pin() - Pins a GEM-TTM object in a region
+ * @gbo:	the GEM TTM object
+ * @pl_flag:	a bitmask of possible memory regions
+ *
+ * Pinning a buffer object ensures that it is not evicted from
+ * a memory region. A pinned buffer object has to be unpinned before
+ * it can be pinned to another region.
+ *
+ * Returns:
+ * 0 on success, or
+ * a negative error code otherwise.
+ */
+int drm_gem_ttm_pin(struct drm_gem_ttm_object *gbo, u32 pl_flag)
+{
+	int i, ret;
+	struct ttm_operation_ctx ctx = { false, false };
+
+	if (gbo->pin_count) {
+		++gbo->pin_count;
+		return 0;
+	}
+
+	drm_gem_ttm_placement(gbo, pl_flag);
+	for (i = 0; i < gbo->placement.num_placement; ++i)
+		gbo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
+
+	ret = ttm_bo_validate(&gbo->bo, &gbo->placement, &ctx);
+	if (ret < 0)
+		return ret;
+
+	gbo->pin_count = 1;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_gem_ttm_pin);
+
+/**
+ * drm_gem_ttm_unpin() - Unpins a GEM-TTM object
+ * @gbo:	the GEM TTM object
+ *
+ * Returns:
+ * 0 on success, or
+ * a negative error code otherwise.
+ */
+int drm_gem_ttm_unpin(struct drm_gem_ttm_object *gbo)
+{
+	int i, ret;
+	struct ttm_operation_ctx ctx = { false, false };
+
+	if (!gbo->pin_count)
+		return 0;
+
+	--gbo->pin_count;
+	if (gbo->pin_count)
+		return 0;
+
+	for (i = 0; i < gbo->placement.num_placement ; ++i)
+		gbo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
+
+	ret = ttm_bo_validate(&gbo->bo, &gbo->placement, &ctx);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_gem_ttm_unpin);
+
+/**
+ * drm_gem_ttm_push_to_system() - \
+	Unpins a GEM TTM object and moves it to system memory
+ * @gbo:	the GEM TTM object
+ *
+ * This operation only works if the caller holds the final pin on the
+ * buffer object.
+ *
+ * Returns:
+ * 0 on success, or
+ * a negative error code otherwise.
+ */
+int drm_gem_ttm_push_to_system(struct drm_gem_ttm_object *gbo)
+{
+	int i, ret;
+	struct ttm_operation_ctx ctx = { false, false };
+
+	if (!gbo->pin_count)
+		return 0;
+
+	--gbo->pin_count;
+	if (gbo->pin_count)
+		return 0;
+
+	if (gbo->kmap.virtual)
+		ttm_bo_kunmap(&gbo->kmap);
+
+	drm_gem_ttm_placement(gbo, TTM_PL_FLAG_SYSTEM);
+	for (i = 0; i < gbo->placement.num_placement ; ++i)
+		gbo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
+
+	ret = ttm_bo_validate(&gbo->bo, &gbo->placement, &ctx);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_gem_ttm_push_to_system);
+
+/**
+ * drm_gem_ttm_kmap() - Maps a GEM TTM object into kernel address space.
+ * @gbo:	the GEM TTM object
+ * @map:	establish a mapping if necessary
+ *
+ * This function maps the buffer object into the kernel's address space
+ * or returns the current mapping. If the parameter map is false, the
+ * function only queries the current mapping, but does not establish a
+ * new one.
+ *
+ * Returns:
+ * The buffers virtual address if mapped, or
+ * NULL is not mapped, or
+ * an ERR_PTR()-encoded error code otherwise.
+ */
+void* drm_gem_ttm_kmap(struct drm_gem_ttm_object *gbo, bool map)
+{
+	int ret;
+
+	if (gbo->kmap.virtual || !map)
+		return gbo->kmap.virtual;
+
+	ret = ttm_bo_kmap(&gbo->bo, 0, gbo->bo.num_pages, &gbo->kmap);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return gbo->kmap.virtual;
+}
+EXPORT_SYMBOL(drm_gem_ttm_kmap);
+
+/**
+ * drm_gem_ttm_kunmap() - Unmaps a GEM TTM object.
+ * @gbo:	the GEM TTM object
+ */
+void drm_gem_ttm_kunmap(struct drm_gem_ttm_object *gbo)
+{
+	if (!gbo->kmap.virtual)
+		return;
+
+	ttm_bo_kunmap(&gbo->kmap);
+	gbo->kmap.virtual = NULL;
+}
+EXPORT_SYMBOL(drm_gem_ttm_kunmap);
+
+bool drm_is_gem_ttm(struct ttm_buffer_object *bo)
+{
+	return (bo->destroy == ttm_buffer_object_destroy);
+}
+EXPORT_SYMBOL(drm_is_gem_ttm);
diff --git a/drivers/gpu/drm/drm_ttm_helper_common.c b/drivers/gpu/drm/drm_ttm_helper_common.c
new file mode 100644
index 000000000000..cacd0f69facc
--- /dev/null
+++ b/drivers/gpu/drm/drm_ttm_helper_common.c
@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <linux/module.h>
+
+MODULE_DESCRIPTION("DRM TTM memory-management helpers");
+MODULE_LICENSE("GPL");
diff --git a/include/drm/drm_gem_ttm_helper.h b/include/drm/drm_gem_ttm_helper.h
new file mode 100644
index 000000000000..662dcb8d4770
--- /dev/null
+++ b/include/drm/drm_gem_ttm_helper.h
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef DRM_GEM_TTM_HELPER_H
+#define DRM_GEM_TTM_HELPER_H
+
+#include <drm/drm_gem.h>
+#include <drm/ttm/ttm_bo_api.h>
+#include <drm/ttm/ttm_placement.h>
+#include <linux/kernel.h> /* for container_of() */
+
+struct filp;
+
+/*
+ * Buffer-object helpers
+ */
+
+/**
+ * struct drm_gem_ttm_object - GEM object backed by TTM-managed memory
+ *
+ * The type struct drm_gem_ttm_object represents a GEM object that is
+ * backed by TTM-managed memory. It can be used for simple frambuffer
+ * devices with dedicated memory. Current supported memory regions are
+ * TTM_PL_SYSTEM and TTM_PL_VRAM. TTM_PL_TT could probably be added if
+ * necessary.
+ */
+struct drm_gem_ttm_object {
+	/**
+	 * GEM object
+	 */
+        struct drm_gem_object gem;
+
+	/**
+	 * TTM buffer object
+	 */
+        struct ttm_buffer_object bo;
+
+	/**
+	 * Mapping information for bo
+	 */
+        struct ttm_bo_kmap_obj kmap;
+
+	/* Supported placements are VRAM and SYSTEM */
+        struct ttm_placement placement;
+        struct ttm_place placements[3];
+
+        int pin_count;
+};
+
+/**
+ * Returns the container of type struct drm_gem_ttm_object
+ * for field bo.
+ * @bo:		the TTM buffer object
+ * Returns:	The containing GEM-TTM object
+ */
+static inline struct drm_gem_ttm_object* drm_gem_ttm_of_bo(
+	struct ttm_buffer_object *bo)
+{
+	return container_of(bo, struct drm_gem_ttm_object, bo);
+}
+
+/**
+ * Returns the container of type struct drm_gem_ttm_object
+ * for field gem.
+ * @gem:	the GEM object
+ * Returns:	The containing GEM-TTM object
+ */
+static inline struct drm_gem_ttm_object* drm_gem_ttm_of_gem(
+	struct drm_gem_object *gem)
+{
+	return container_of(gem, struct drm_gem_ttm_object, gem);
+}
+
+struct drm_gem_ttm_object* drm_gem_ttm_create(struct drm_device *dev,
+					      struct ttm_bo_device* bdev,
+					      unsigned long size,
+					      uint32_t pg_align,
+					      bool interruptible);
+void drm_gem_ttm_put(struct drm_gem_ttm_object *gbo);
+int drm_gem_ttm_reserve(struct drm_gem_ttm_object *gbo, bool no_wait);
+void drm_gem_ttm_unreserve(struct drm_gem_ttm_object *gbo);
+u64 drm_gem_ttm_mmap_offset(struct drm_gem_ttm_object *gbo);
+s64 drm_gem_ttm_vram_offset(struct drm_gem_ttm_object *gbo);
+int drm_gem_ttm_pin(struct drm_gem_ttm_object *gbo, u32 pl_flag);
+int drm_gem_ttm_unpin(struct drm_gem_ttm_object *gbo);
+int drm_gem_ttm_push_to_system(struct drm_gem_ttm_object *gbo);
+void* drm_gem_ttm_kmap(struct drm_gem_ttm_object *gbo, bool map);
+void drm_gem_ttm_kunmap(struct drm_gem_ttm_object *gbo);
+
+bool drm_is_gem_ttm(struct ttm_buffer_object *bo);
+
+#endif
