diff --git a/drivers/gpu/drm/loongson/Makefile b/drivers/gpu/drm/loongson/Makefile
index 91e72bd900c1..cdc60ec975e4 100644
--- a/drivers/gpu/drm/loongson/Makefile
+++ b/drivers/gpu/drm/loongson/Makefile
@@ -9,6 +9,7 @@ loongson-y := \
 	lsdc_gfxpll.o \
 	lsdc_i2c.o \
 	lsdc_irq.o \
+	lsdc_output.o \
 	lsdc_output_7a1000.o \
 	lsdc_output_7a2000.o \
 	lsdc_plane.o \
@@ -16,7 +17,11 @@ loongson-y := \
 	lsdc_probe.o \
 	lsdc_ttm.o
 
+loongson-y += \
+	loonggpu_pci_drv.o
+
 loongson-y += loongson_device.o \
+	      loongson_drv.o \
 	      loongson_module.o
 
 obj-$(CONFIG_DRM_LOONGSON) += loongson.o
diff --git a/drivers/gpu/drm/loongson/loonggpu_pci_drv.c b/drivers/gpu/drm/loongson/loonggpu_pci_drv.c
new file mode 100644
index 000000000000..a34c213171e0
--- /dev/null
+++ b/drivers/gpu/drm/loongson/loonggpu_pci_drv.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Authors:
+ *      Sui Jingfeng <sui.jingfeng@linux.dev>
+ */
+
+#include <linux/component.h>
+#include <linux/pci.h>
+
+#include <drm/drm_device.h>
+#include <drm/drm_print.h>
+
+#include "loongson_module.h"
+#include "loonggpu_pci_drv.h"
+
+static int loonggpu_get_version(struct loonggpu_device *gpu)
+{
+	u32 hw_info = loong_rreg32(gpu, 0x8C);
+	u8 host_id;
+	u8 revision;
+
+	/* LoongGPU hardware info */
+	gpu->ver_major = (hw_info >> 8) & 0x0F;
+	gpu->ver_minor = (hw_info & 0xF0) >> 4;
+	revision = hw_info & 0x0F;
+	host_id = (hw_info >> 16) & 0xFF;
+
+	drm_info(gpu->drm, "LoongGPU(TM): LG%x%x0, revision: %x, Host: %s\n",
+		 gpu->ver_major, gpu->ver_minor, revision,
+		 host_id ? "LS2K2000" : "LS7A2000");
+
+	return 0;
+}
+
+static irqreturn_t loonggpu_irq_handler(int irq, void *arg)
+{
+	struct loonggpu_device *gpu = arg;
+
+	drm_info(gpu->drm, "LoongGPU interrupted\n");
+
+	return IRQ_HANDLED;
+}
+
+static int loonggpu_component_bind(struct device *dev,
+				   struct device *master,
+				   void *data)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct drm_device *drm = data;
+	struct loonggpu_device *gpu;
+	int ret;
+
+	gpu = devm_kzalloc(dev, sizeof(*gpu), GFP_KERNEL);
+	if (!gpu)
+		return -ENOMEM;
+
+	gpu->reg_base = pcim_iomap(pdev, 0, 0);
+	if (!gpu->reg_base)
+		return -ENOMEM;
+
+	gpu->pdev = pdev;
+	gpu->drm = drm;
+
+	loonggpu_get_version(gpu);
+
+	dev_set_drvdata(dev, gpu);
+
+	ret = devm_request_irq(dev,
+			       pdev->irq,
+			       loonggpu_irq_handler,
+			       IRQF_SHARED,
+			       dev_name(dev),
+			       gpu);
+	if (ret)
+		return ret;
+
+	drm_info(gpu->drm, "LoongGPU irq: %d\n", pdev->irq);
+
+	return 0;
+}
+
+static void loonggpu_component_unbind(struct device *dev,
+				      struct device *master,
+				      void *data)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct loonggpu_device *gpu = dev_get_drvdata(dev);
+
+	if (gpu) {
+		pcim_iounmap(pdev, gpu->reg_base);
+		devm_kfree(dev, gpu);
+	}
+}
+
+static const struct component_ops loonggpu_component_ops = {
+	.bind = loonggpu_component_bind,
+	.unbind = loonggpu_component_unbind,
+};
+
+static int loonggpu_pci_probe(struct pci_dev *pdev,
+			      const struct pci_device_id *ent)
+{
+	int ret;
+
+	ret = pcim_enable_device(pdev);
+	if (ret)
+		return ret;
+
+	pci_set_master(pdev);
+
+	dev_info(&pdev->dev, "LoongGPU PCI driver probed\n");
+
+	return component_add(&pdev->dev, &loonggpu_component_ops);
+}
+
+static void loonggpu_pci_remove(struct pci_dev *pdev)
+{
+	component_del(&pdev->dev, &loonggpu_component_ops);
+}
+
+static const struct pci_device_id loonggpu_pci_id_list[] = {
+	{PCI_VDEVICE(LOONGSON, 0x7a25), CHIP_LS7A2000},
+	{ },
+};
+
+struct pci_driver loonggpu_pci_driver = {
+	.name = "LoongGPU",
+	.id_table = loonggpu_pci_id_list,
+	.probe = loonggpu_pci_probe,
+	.remove = loonggpu_pci_remove,
+};
+
+void loonggpu_pci_match_add(struct device *master,
+			    struct component_match **matchptr)
+{
+	struct pci_dev *gpu;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(loonggpu_pci_id_list); ++i) {
+		unsigned int did = loonggpu_pci_id_list[i].device;
+
+		gpu = pci_get_device(PCI_VENDOR_ID_LOONGSON, did, NULL);
+		if (gpu) {
+			component_match_add(master, matchptr,
+					    component_compare_dev, &gpu->dev);
+			pci_dev_put(gpu);
+
+			dev_dbg(master, "match added, name: %s, %u\n",
+				dev_name(&gpu->dev), i);
+			return;
+		}
+	}
+}
+
+MODULE_DEVICE_TABLE(pci, loonggpu_pci_id_list);
diff --git a/drivers/gpu/drm/loongson/loonggpu_pci_drv.h b/drivers/gpu/drm/loongson/loonggpu_pci_drv.h
new file mode 100644
index 000000000000..35b176ff01d0
--- /dev/null
+++ b/drivers/gpu/drm/loongson/loonggpu_pci_drv.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __LOONGGPU_PCI_DRV_H__
+#define __LOONGGPU_PCI_DRV_H__
+
+#include <linux/component.h>
+#include <linux/pci.h>
+
+struct loonggpu_device {
+	struct pci_dev *pdev;
+	struct drm_device *drm;
+
+	void __iomem *reg_base;
+
+	u32 ver_major;
+	u32 ver_minor;
+	u32 revision;
+};
+
+static inline u32 loong_rreg32(struct loonggpu_device *ldev, u32 offset)
+{
+	return readl(ldev->reg_base + offset);
+}
+
+static inline void loong_wreg32(struct loonggpu_device *ldev, u32 offset, u32 val)
+{
+	writel(val, ldev->reg_base + offset);
+}
+
+void loonggpu_pci_match_add(struct device *master,
+			    struct component_match **matchptr);
+
+#endif
diff --git a/drivers/gpu/drm/loongson/loongson_device.c b/drivers/gpu/drm/loongson/loongson_device.c
index 9986c8a2a255..f0e3d6544291 100644
--- a/drivers/gpu/drm/loongson/loongson_device.c
+++ b/drivers/gpu/drm/loongson/loongson_device.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/pci.h>
+#include <linux/platform_device.h>
 
 #include "lsdc_drv.h"
 
diff --git a/drivers/gpu/drm/loongson/loongson_drv.c b/drivers/gpu/drm/loongson/loongson_drv.c
new file mode 100644
index 000000000000..b5273bbf03e6
--- /dev/null
+++ b/drivers/gpu/drm/loongson/loongson_drv.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Authors:
+ *      Sui Jingfeng <sui.jingfeng@linux.dev>
+ */
+
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <drm/drm_aperture.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fbdev_ttm.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
+
+#include "loonggpu_pci_drv.h"
+#include "loongson_module.h"
+#include "lsdc_drv.h"
+#include "lsdc_gem.h"
+#include "lsdc_output.h"
+#include "lsdc_ttm.h"
+
+static struct platform_device *loongson_dev;
+
+static void loongson_device_postfini(void *data)
+{
+	struct platform_device *proxy = data;
+
+	platform_device_unregister(proxy);
+}
+
+int loongson_device_preinit(struct device *parent, void *data)
+{
+	struct platform_device *proxy;
+	int ret;
+
+	proxy = platform_device_register_resndata(parent,
+						  DRIVER_NAME,
+						  PLATFORM_DEVID_NONE,
+						  NULL, 0,
+						  data, sizeof(void *));
+	if (IS_ERR(proxy)) {
+		dev_err(parent, "failed to register loongson proxy device\n");
+		return PTR_ERR(proxy);
+	}
+
+	ret = devm_add_action_or_reset(parent, loongson_device_postfini, proxy);
+	if (ret)
+		return ret;
+
+	loongson_dev = proxy;
+
+	return 0;
+}
+
+static int loongson_drm_master_bind(struct device *dev)
+{
+	struct drm_device *ddev = dev_get_drvdata(dev->parent);
+	struct lsdc_device *ldev = to_lsdc(ddev);
+	const struct lsdc_desc *descp = ldev->descp;
+	int num_pipe = descp->num_of_crtc;
+	int ret;
+
+	loongson_gfxpll_create(&ldev->base, &ldev->gfxpll);
+
+	ret = lsdc_mode_config_init(ddev, descp);
+	if (ret)
+		return ret;
+
+	ret = component_bind_all(dev, ddev);
+	if (ret) {
+		dev_err(dev, "master bind all failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = lsdc_modeset_init(ldev, num_pipe, descp->funcs, loongson_vblank);
+	if (ret)
+		return ret;
+
+	if (loongson_vblank) {
+		ret = drm_vblank_init(ddev, num_pipe);
+		if (ret)
+			return ret;
+	}
+
+	lsdc_gem_init(ddev);
+
+	ret = lsdc_ttm_init(ddev);
+	if (ret) {
+		drm_err(ddev, "Memory manager init failed: %d\n", ret);
+		return ret;
+	}
+
+	drm_mode_config_reset(ddev);
+
+	drmm_kms_helper_poll_init(ddev);
+
+	ret = drm_dev_register(ddev, 0);
+	if (ret)
+		return ret;
+
+	drm_fbdev_ttm_setup(ddev, 32);
+
+	return 0;
+}
+
+static void loongson_drm_master_unbind(struct device *dev)
+{
+	struct drm_device *ddev = dev_get_drvdata(dev->parent);
+
+	drm_atomic_helper_shutdown(ddev);
+
+	component_unbind_all(dev, ddev);
+}
+
+static const struct component_master_ops loongson_drm_master_ops = {
+	.bind = loongson_drm_master_bind,
+	.unbind = loongson_drm_master_unbind,
+};
+
+static int loongson_drm_driver_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct drm_device *ddev = *(void **)dev->platform_data;
+	struct component_match *matches = NULL;
+
+	dev_set_drvdata(dev, ddev);
+
+	lsdc_output_match_add(dev, &matches);
+
+	lsdc_pci_match_add(dev, &matches);
+
+	loonggpu_pci_match_add(dev, &matches);
+
+	return component_master_add_with_match(dev,
+					       &loongson_drm_master_ops,
+					       matches);
+}
+
+static void loongson_drm_driver_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+
+	component_master_del(dev, &loongson_drm_master_ops);
+}
+
+struct platform_driver loongson_drm_platform_driver = {
+	.probe = loongson_drm_driver_probe,
+	.remove_new = loongson_drm_driver_remove,
+	.driver = {
+		.name = DRIVER_NAME,
+	},
+};
diff --git a/drivers/gpu/drm/loongson/loongson_module.c b/drivers/gpu/drm/loongson/loongson_module.c
index d2a51bd395f6..836b6a40a9f1 100644
--- a/drivers/gpu/drm/loongson/loongson_module.c
+++ b/drivers/gpu/drm/loongson/loongson_module.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/pci.h>
+#include <linux/platform_device.h>
 
 #include <video/nomodeset.h>
 
@@ -19,15 +20,50 @@ module_param_named(vblank, loongson_vblank, int, 0400);
 
 static int __init loongson_module_init(void)
 {
+	int ret;
+
 	if (!loongson_modeset || video_firmware_drivers_only())
 		return -ENODEV;
 
-	return pci_register_driver(&lsdc_pci_driver);
+	ret = pci_register_driver(&lsdc_pci_driver);
+	if (ret)
+		return ret;
+
+	ret = pci_register_driver(&loonggpu_pci_driver);
+	if (ret)
+		goto unregister_lsdc_pci_driver;
+
+	ret = platform_driver_register(&loongson_drm_platform_driver);
+	if (ret)
+		goto unregister_loonggpu_pci_driver;
+
+	ret = platform_driver_register(&lsdc_output_platform_driver);
+	if (ret)
+		goto unregister_loongson_drm_platform_driver;
+
+	return 0;
+
+unregister_loongson_drm_platform_driver:
+	platform_driver_unregister(&loongson_drm_platform_driver);
+
+unregister_loonggpu_pci_driver:
+	pci_unregister_driver(&loonggpu_pci_driver);
+
+unregister_lsdc_pci_driver:
+	pci_unregister_driver(&lsdc_pci_driver);
+
+	return ret;
 }
 module_init(loongson_module_init);
 
 static void __exit loongson_module_exit(void)
 {
+	platform_driver_unregister(&loongson_drm_platform_driver);
+
 	pci_unregister_driver(&lsdc_pci_driver);
+
+	pci_unregister_driver(&loonggpu_pci_driver);
+
+	platform_driver_unregister(&lsdc_output_platform_driver);
 }
 module_exit(loongson_module_exit);
diff --git a/drivers/gpu/drm/loongson/loongson_module.h b/drivers/gpu/drm/loongson/loongson_module.h
index 931c17521bf0..ba29eba2e7ef 100644
--- a/drivers/gpu/drm/loongson/loongson_module.h
+++ b/drivers/gpu/drm/loongson/loongson_module.h
@@ -6,7 +6,24 @@
 #ifndef __LOONGSON_MODULE_H__
 #define __LOONGSON_MODULE_H__
 
+#define DRIVER_AUTHOR               "Sui Jingfeng <sui.jingfeng@linux.dev>"
+#define DRIVER_NAME                 "loongson"
+#define DRIVER_DESC                 "drm driver for loongson graphics"
+#define DRIVER_DATE                 "20220701"
+#define DRIVER_MAJOR                1
+#define DRIVER_MINOR                0
+#define DRIVER_PATCHLEVEL           0
+
+enum loongson_chip_id {
+	CHIP_LS7A1000 = 0,
+	CHIP_LS7A2000 = 1,
+	CHIP_LS_LAST,
+};
+
 extern int loongson_vblank;
 extern struct pci_driver lsdc_pci_driver;
+extern struct pci_driver loonggpu_pci_driver;
+extern struct platform_driver lsdc_output_platform_driver;
+extern struct platform_driver loongson_drm_platform_driver;
 
 #endif
diff --git a/drivers/gpu/drm/loongson/lsdc_drv.c b/drivers/gpu/drm/loongson/lsdc_drv.c
index adc7344d2f80..28f8ee5c3fc5 100644
--- a/drivers/gpu/drm/loongson/lsdc_drv.c
+++ b/drivers/gpu/drm/loongson/lsdc_drv.c
@@ -3,10 +3,12 @@
  * Copyright (C) 2023 Loongson Technology Corporation Limited
  */
 
+#include <linux/aperture.h>
+#include <linux/component.h>
 #include <linux/pci.h>
+#include <linux/platform_device.h>
 #include <linux/vgaarb.h>
 
-#include <drm/drm_aperture.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_drv.h>
@@ -22,14 +24,6 @@
 #include "lsdc_gem.h"
 #include "lsdc_ttm.h"
 
-#define DRIVER_AUTHOR               "Sui Jingfeng <suijingfeng@loongson.cn>"
-#define DRIVER_NAME                 "loongson"
-#define DRIVER_DESC                 "drm driver for loongson graphics"
-#define DRIVER_DATE                 "20220701"
-#define DRIVER_MAJOR                1
-#define DRIVER_MINOR                0
-#define DRIVER_PATCHLEVEL           0
-
 DEFINE_DRM_GEM_FOPS(lsdc_gem_fops);
 
 static const struct drm_driver lsdc_drm_driver = {
@@ -57,41 +51,16 @@ static const struct drm_mode_config_funcs lsdc_mode_config_funcs = {
 
 /* Display related */
 
-static int lsdc_modeset_init(struct lsdc_device *ldev,
-			     unsigned int num_crtc,
-			     const struct lsdc_kms_funcs *funcs,
-			     bool has_vblank)
+int lsdc_modeset_init(struct lsdc_device *ldev,
+		      unsigned int num_crtc,
+		      const struct lsdc_kms_funcs *funcs,
+		      bool has_vblank)
 {
 	struct drm_device *ddev = &ldev->base;
 	struct lsdc_display_pipe *dispipe;
 	unsigned int i;
 	int ret;
 
-	for (i = 0; i < num_crtc; i++) {
-		dispipe = &ldev->dispipe[i];
-
-		/* We need an index before crtc is initialized */
-		dispipe->index = i;
-
-		ret = funcs->create_i2c(ddev, dispipe, i);
-		if (ret)
-			return ret;
-	}
-
-	for (i = 0; i < num_crtc; i++) {
-		struct i2c_adapter *ddc = NULL;
-
-		dispipe = &ldev->dispipe[i];
-		if (dispipe->li2c)
-			ddc = &dispipe->li2c->adapter;
-
-		ret = funcs->output_init(ddev, dispipe, ddc, i);
-		if (ret)
-			return ret;
-
-		ldev->num_output++;
-	}
-
 	for (i = 0; i < num_crtc; i++) {
 		dispipe = &ldev->dispipe[i];
 
@@ -120,8 +89,8 @@ static const struct drm_mode_config_helper_funcs lsdc_mode_config_helper_funcs =
 	.atomic_commit_tail = drm_atomic_helper_commit_tail,
 };
 
-static int lsdc_mode_config_init(struct drm_device *ddev,
-				 const struct lsdc_desc *descp)
+int lsdc_mode_config_init(struct drm_device *ddev,
+			  const struct lsdc_desc *descp)
 {
 	int ret;
 
@@ -177,9 +146,10 @@ static int lsdc_get_dedicated_vram(struct lsdc_device *ldev,
 	base = pci_resource_start(pdev_gpu, 2);
 	size = pci_resource_len(pdev_gpu, 2);
 
+	pci_dev_put(pdev_gpu);
+
 	ldev->vram_base = base;
 	ldev->vram_size = size;
-	ldev->gpu = pdev_gpu;
 
 	drm_info(ddev, "Dedicated vram start: 0x%llx, size: %uMiB\n",
 		 (u64)base, (u32)(size >> 20));
@@ -187,80 +157,62 @@ static int lsdc_get_dedicated_vram(struct lsdc_device *ldev,
 	return (size > SZ_1M) ? 0 : -ENODEV;
 }
 
-static struct lsdc_device *
-lsdc_create_device(struct pci_dev *pdev,
-		   const struct lsdc_desc *descp,
-		   const struct drm_driver *driver)
-{
-	struct lsdc_device *ldev;
-	struct drm_device *ddev;
-	int ret;
-
-	ldev = devm_drm_dev_alloc(&pdev->dev, driver, struct lsdc_device, base);
-	if (IS_ERR(ldev))
-		return ldev;
-
-	ldev->dc = pdev;
-	ldev->descp = descp;
+/* For multiple GPU driver instance co-exixt in the system */
 
-	ddev = &ldev->base;
+static unsigned int lsdc_vga_set_decode(struct pci_dev *pdev, bool state)
+{
+	return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+}
 
-	loongson_gfxpll_create(ddev, &ldev->gfxpll);
+static int lsdc_component_bind(struct device *dev, struct device *master, void *data)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct drm_device *drm = data;
+	struct lsdc_device *ldev = to_lsdc(drm);
+	const struct lsdc_desc *descp = ldev->descp;
+	int ret;
 
 	ret = lsdc_get_dedicated_vram(ldev, pdev, descp);
-	if (ret) {
-		drm_err(ddev, "Init VRAM failed: %d\n", ret);
-		return ERR_PTR(ret);
-	}
-
-	ret = drm_aperture_remove_conflicting_framebuffers(ldev->vram_base,
-							   ldev->vram_size,
-							   driver);
-	if (ret) {
-		drm_err(ddev, "Remove firmware framebuffers failed: %d\n", ret);
-		return ERR_PTR(ret);
-	}
-
-	ret = lsdc_ttm_init(ldev);
-	if (ret) {
-		drm_err(ddev, "Memory manager init failed: %d\n", ret);
-		return ERR_PTR(ret);
-	}
-
-	lsdc_gem_init(ddev);
-
-	/* Bar 0 of the DC device contains the MMIO register's base address */
-	ldev->reg_base = pcim_iomap(pdev, 0, 0);
-	if (!ldev->reg_base)
-		return ERR_PTR(-ENODEV);
-
-	spin_lock_init(&ldev->reglock);
+	if (ret)
+		return ret;
 
-	ret = lsdc_mode_config_init(ddev, descp);
+	ret = aperture_remove_conflicting_devices(ldev->vram_base,
+						  ldev->vram_size,
+						  DRIVER_NAME);
 	if (ret)
-		return ERR_PTR(ret);
+		return ret;
 
-	ret = lsdc_modeset_init(ldev, descp->num_of_crtc, descp->funcs,
-				loongson_vblank);
+	ret = devm_request_irq(dev,
+			       pdev->irq,
+			       descp->funcs->irq_handler,
+			       IRQF_SHARED,
+			       dev_name(dev),
+			       drm);
 	if (ret)
-		return ERR_PTR(ret);
+		return ret;
 
-	drm_mode_config_reset(ddev);
+	dev_info(dev, "lsdc irq: %d\n", pdev->irq);
 
-	return ldev;
-}
+	vga_client_register(pdev, lsdc_vga_set_decode);
 
-/* For multiple GPU driver instance co-exixt in the system */
+	return 0;
+}
 
-static unsigned int lsdc_vga_set_decode(struct pci_dev *pdev, bool state)
+static void lsdc_component_unbind(struct device *dev, struct device *master, void *data)
 {
-	return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	vga_client_unregister(pdev);
 }
 
+static const struct component_ops lsdc_component_ops = {
+	.bind = lsdc_component_bind,
+	.unbind = lsdc_component_unbind,
+};
+
 static int lsdc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	const struct lsdc_desc *descp;
-	struct drm_device *ddev;
 	struct lsdc_device *ldev;
 	int ret;
 
@@ -278,58 +230,58 @@ static int lsdc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	if (ret)
 		return ret;
 
-	dev_info(&pdev->dev, "Found %s, revision: %u",
+	dev_info(&pdev->dev, "Found %s, revision: %u\n",
 		 to_loongson_gfx(descp)->model, pdev->revision);
 
-	ldev = lsdc_create_device(pdev, descp, &lsdc_drm_driver);
+	ldev = devm_drm_dev_alloc(&pdev->dev, &lsdc_drm_driver,
+				  struct lsdc_device, base);
 	if (IS_ERR(ldev))
 		return PTR_ERR(ldev);
 
-	ddev = &ldev->base;
-
-	pci_set_drvdata(pdev, ddev);
-
-	vga_client_register(pdev, lsdc_vga_set_decode);
+	pci_set_drvdata(pdev, ldev);
+	ldev->dc = pdev;
+	ldev->descp = descp;
 
-	drm_kms_helper_poll_init(ddev);
+	/* Bar 0 of the DC device contains the MMIO register's base address */
+	ldev->reg_base = pcim_iomap(pdev, 0, 0);
+	if (!ldev->reg_base)
+		return -ENODEV;
 
-	if (loongson_vblank) {
-		ret = drm_vblank_init(ddev, descp->num_of_crtc);
-		if (ret)
-			return ret;
+	spin_lock_init(&ldev->reglock);
 
-		ret = devm_request_irq(&pdev->dev, pdev->irq,
-				       descp->funcs->irq_handler,
-				       IRQF_SHARED,
-				       dev_name(&pdev->dev), ddev);
-		if (ret) {
-			drm_err(ddev, "Failed to register interrupt: %d\n", ret);
-			return ret;
-		}
+	ret = lsdc_i2c_preinit(&pdev->dev);
+	if (ret)
+		return ret;
 
-		drm_info(ddev, "registered irq: %u\n", pdev->irq);
+	ret = lsdc_output_preinit(&pdev->dev, descp);
+	if (ret) {
+		dev_err(&pdev->dev, "Output preinit failed: %d\n", ret);
+		return ret;
 	}
 
-	ret = drm_dev_register(ddev, 0);
-	if (ret)
+	ret = component_add(&pdev->dev, &lsdc_component_ops);
+	if (ret) {
+		dev_err(&pdev->dev, "Add as a subcomponent failed: %d\n", ret);
 		return ret;
+	}
 
-	drm_fbdev_ttm_setup(ddev, 32);
+	ret = loongson_device_preinit(&pdev->dev, (void **)&ldev->base);
+	if (ret) {
+		dev_err(&pdev->dev, "Proxy drm device failed: %d\n", ret);
+		return ret;
+	}
 
 	return 0;
 }
 
 static void lsdc_pci_remove(struct pci_dev *pdev)
 {
-	struct drm_device *ddev = pci_get_drvdata(pdev);
+	struct lsdc_device *ldev = pci_get_drvdata(pdev);
+	struct drm_device *ddev = &ldev->base;
 
 	drm_dev_unregister(ddev);
-	drm_atomic_helper_shutdown(ddev);
-}
 
-static void lsdc_pci_shutdown(struct pci_dev *pdev)
-{
-	drm_atomic_helper_shutdown(pci_get_drvdata(pdev));
+	component_del(&pdev->dev, &lsdc_component_ops);
 }
 
 static int lsdc_drm_freeze(struct drm_device *ddev)
@@ -383,7 +335,8 @@ static int lsdc_drm_freeze(struct drm_device *ddev)
 static int lsdc_drm_resume(struct device *dev)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
-	struct drm_device *ddev = pci_get_drvdata(pdev);
+	struct lsdc_device *ldev = pci_get_drvdata(pdev);
+	struct drm_device *ddev = &ldev->base;
 
 	return drm_mode_config_helper_resume(ddev);
 }
@@ -391,7 +344,8 @@ static int lsdc_drm_resume(struct device *dev)
 static int lsdc_pm_freeze(struct device *dev)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
-	struct drm_device *ddev = pci_get_drvdata(pdev);
+	struct lsdc_device *ldev = pci_get_drvdata(pdev);
+	struct drm_device *ddev = &ldev->base;
 
 	return lsdc_drm_freeze(ddev);
 }
@@ -452,10 +406,31 @@ struct pci_driver lsdc_pci_driver = {
 	.id_table = lsdc_pciid_list,
 	.probe = lsdc_pci_probe,
 	.remove = lsdc_pci_remove,
-	.shutdown = lsdc_pci_shutdown,
 	.driver.pm = &lsdc_pm_ops,
 };
 
+void lsdc_pci_match_add(struct device *master,
+			struct component_match **matchptr)
+{
+	struct pci_dev *dc;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(lsdc_pciid_list); ++i) {
+		unsigned int did = lsdc_pciid_list[i].device;
+
+		dc = pci_get_device(PCI_VENDOR_ID_LOONGSON, did, NULL);
+		if (dc) {
+			component_match_add(master, matchptr,
+					    component_compare_dev, &dc->dev);
+			pci_dev_put(dc);
+
+			dev_dbg(master, "match added, name: %s, %u\n",
+				dev_name(&dc->dev), i);
+			return;
+		}
+	}
+}
+
 MODULE_DEVICE_TABLE(pci, lsdc_pciid_list);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/gpu/drm/loongson/lsdc_drv.h b/drivers/gpu/drm/loongson/lsdc_drv.h
index fbf2d760ef27..71d7e6288028 100644
--- a/drivers/gpu/drm/loongson/lsdc_drv.h
+++ b/drivers/gpu/drm/loongson/lsdc_drv.h
@@ -16,6 +16,8 @@
 #include <drm/drm_plane.h>
 #include <drm/ttm/ttm_device.h>
 
+#include "loongson_module.h"
+
 #include "lsdc_i2c.h"
 #include "lsdc_irq.h"
 #include "lsdc_gfxpll.h"
@@ -38,15 +40,17 @@
  * display pipe 1 = crtc1 + dvo1 + encoder1 + connectro1 + cursor1 + primary1
  */
 
-enum loongson_chip_id {
-	CHIP_LS7A1000 = 0,
-	CHIP_LS7A2000 = 1,
-	CHIP_LS_LAST,
-};
-
 const struct lsdc_desc *
 lsdc_device_probe(struct pci_dev *pdev, enum loongson_chip_id chip);
 
+void lsdc_pci_match_add(struct device *master,
+			struct component_match **matchptr);
+
+int lsdc_mode_config_init(struct drm_device *ddev,
+			  const struct lsdc_desc *descp);
+
+int loongson_device_preinit(struct device *parent, void *data);
+
 struct lsdc_kms_funcs;
 
 /* DC specific */
@@ -167,47 +171,23 @@ struct lsdc_cursor {
 	struct lsdc_device *ldev;
 };
 
-struct lsdc_output {
-	struct drm_encoder encoder;
-	struct drm_connector connector;
-};
-
-static inline struct lsdc_output *
-connector_to_lsdc_output(struct drm_connector *connector)
-{
-	return container_of(connector, struct lsdc_output, connector);
-}
-
-static inline struct lsdc_output *
-encoder_to_lsdc_output(struct drm_encoder *encoder)
-{
-	return container_of(encoder, struct lsdc_output, encoder);
-}
-
 struct lsdc_display_pipe {
 	struct lsdc_crtc crtc;
 	struct lsdc_primary primary;
 	struct lsdc_cursor cursor;
-	struct lsdc_output output;
-	struct lsdc_i2c *li2c;
+	struct lsdc_output *output;
 	unsigned int index;
 };
 
-static inline struct lsdc_display_pipe *
-output_to_display_pipe(struct lsdc_output *output)
-{
-	return container_of(output, struct lsdc_display_pipe, output);
-}
-
 struct lsdc_kms_funcs {
 	irqreturn_t (*irq_handler)(int irq, void *arg);
 
-	int (*create_i2c)(struct drm_device *ddev,
-			  struct lsdc_display_pipe *dispipe,
-			  unsigned int index);
+	int (*create_i2c)(struct device *parent,
+			  unsigned int index,
+			  struct i2c_adapter **ppadapter);
 
 	int (*output_init)(struct drm_device *ddev,
-			   struct lsdc_display_pipe *dispipe,
+			   struct lsdc_output *output,
 			   struct i2c_adapter *ddc,
 			   unsigned int index);
 
@@ -284,6 +264,7 @@ struct lsdc_device {
 	resource_size_t gtt_size;
 
 	struct lsdc_display_pipe dispipe[LSDC_NUM_CRTC];
+	struct i2c_adapter *i2c[LSDC_NUM_CRTC];
 
 	struct lsdc_gem gem;
 
@@ -341,6 +322,11 @@ int ls7a2000_cursor_plane_init(struct drm_device *ddev,
 			       struct drm_plane *plane,
 			       unsigned int index);
 
+int lsdc_modeset_init(struct lsdc_device *ldev,
+		      unsigned int num_crtc,
+		      const struct lsdc_kms_funcs *funcs,
+		      bool has_vblank);
+
 /* Registers access helpers */
 
 static inline u32 lsdc_rreg32(struct lsdc_device *ldev, u32 offset)
diff --git a/drivers/gpu/drm/loongson/lsdc_i2c.c b/drivers/gpu/drm/loongson/lsdc_i2c.c
index ce90c25536d2..0ce5007fc0e6 100644
--- a/drivers/gpu/drm/loongson/lsdc_i2c.c
+++ b/drivers/gpu/drm/loongson/lsdc_i2c.c
@@ -15,7 +15,7 @@
  */
 static void __lsdc_gpio_i2c_set(struct lsdc_i2c * const li2c, int mask, int state)
 {
-	struct lsdc_device *ldev = to_lsdc(li2c->ddev);
+	struct lsdc_device *ldev = li2c->lsdc;
 	unsigned long flags;
 	u8 val;
 
@@ -51,7 +51,7 @@ static void __lsdc_gpio_i2c_set(struct lsdc_i2c * const li2c, int mask, int stat
  */
 static int __lsdc_gpio_i2c_get(struct lsdc_i2c * const li2c, int mask)
 {
-	struct lsdc_device *ldev = to_lsdc(li2c->ddev);
+	struct lsdc_device *ldev = li2c->lsdc;
 	unsigned long flags;
 	u8 val;
 
@@ -98,7 +98,7 @@ static int lsdc_gpio_i2c_get_scl(void *i2c)
 	return __lsdc_gpio_i2c_get(li2c, li2c->scl);
 }
 
-static void lsdc_destroy_i2c(struct drm_device *ddev, void *data)
+static void lsdc_destroy_i2c(void *data)
 {
 	struct lsdc_i2c *li2c = (struct lsdc_i2c *)data;
 
@@ -114,11 +114,10 @@ static void lsdc_destroy_i2c(struct drm_device *ddev, void *data)
  * @reg_base: gpio reg base
  * @index: output channel index, 0 for PIPE0, 1 for PIPE1
  */
-int lsdc_create_i2c_chan(struct drm_device *ddev,
-			 struct lsdc_display_pipe *dispipe,
-			 unsigned int index)
+int lsdc_create_i2c_chan(struct device *parent, unsigned int index,
+			 struct i2c_adapter **ppadapter)
 {
-	struct lsdc_device *ldev = to_lsdc(ddev);
+	struct lsdc_device *ldev = dev_get_drvdata(parent);
 	struct i2c_adapter *adapter;
 	struct lsdc_i2c *li2c;
 	int ret;
@@ -127,8 +126,6 @@ int lsdc_create_i2c_chan(struct drm_device *ddev,
 	if (!li2c)
 		return -ENOMEM;
 
-	dispipe->li2c = li2c;
-
 	if (index == 0) {
 		li2c->sda = 0x01;  /* pin 0 */
 		li2c->scl = 0x02;  /* pin 1 */
@@ -139,7 +136,7 @@ int lsdc_create_i2c_chan(struct drm_device *ddev,
 		return -ENOENT;
 	}
 
-	li2c->ddev = ddev;
+	li2c->lsdc = ldev;
 	li2c->dir_reg = ldev->reg_base + LS7A_DC_GPIO_DIR_REG;
 	li2c->dat_reg = ldev->reg_base + LS7A_DC_GPIO_DAT_REG;
 
@@ -154,7 +151,7 @@ int lsdc_create_i2c_chan(struct drm_device *ddev,
 	adapter = &li2c->adapter;
 	adapter->algo_data = &li2c->bit;
 	adapter->owner = THIS_MODULE;
-	adapter->dev.parent = ddev->dev;
+	adapter->dev.parent = parent;
 	adapter->nr = -1;
 
 	snprintf(adapter->name, sizeof(adapter->name), "lsdc-i2c%u", index);
@@ -167,12 +164,30 @@ int lsdc_create_i2c_chan(struct drm_device *ddev,
 		return ret;
 	}
 
-	ret = drmm_add_action_or_reset(ddev, lsdc_destroy_i2c, li2c);
+	ret = devm_add_action_or_reset(parent, lsdc_destroy_i2c, li2c);
 	if (ret)
 		return ret;
 
-	drm_info(ddev, "%s(sda pin mask=%u, scl pin mask=%u) created\n",
-		 adapter->name, li2c->sda, li2c->scl);
+	*ppadapter = adapter;
+
+	dev_info(parent, "%s(sda pin mask=%u, scl pin mask=%u) created\n",
+		 dev_name(&adapter->dev), li2c->sda, li2c->scl);
+
+	return 0;
+}
+
+int lsdc_i2c_preinit(struct device *parent)
+{
+	struct lsdc_device *ldev = dev_get_drvdata(parent);
+	const struct lsdc_desc *descp = ldev->descp;
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < descp->num_of_crtc; ++i) {
+		ret = descp->funcs->create_i2c(parent, i, &ldev->i2c[i]);
+		if (ret)
+			return ret;
+	}
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/loongson/lsdc_i2c.h b/drivers/gpu/drm/loongson/lsdc_i2c.h
index 88cd1a1817a5..59ed7f90beac 100644
--- a/drivers/gpu/drm/loongson/lsdc_i2c.h
+++ b/drivers/gpu/drm/loongson/lsdc_i2c.h
@@ -9,10 +9,12 @@
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 
+struct lsdc_device;
+
 struct lsdc_i2c {
 	struct i2c_adapter adapter;
 	struct i2c_algo_bit_data bit;
-	struct drm_device *ddev;
+	struct lsdc_device *lsdc;
 	void __iomem *dir_reg;
 	void __iomem *dat_reg;
 	/* pin bit mask */
@@ -20,10 +22,9 @@ struct lsdc_i2c {
 	u8 scl;
 };
 
-struct lsdc_display_pipe;
+int lsdc_create_i2c_chan(struct device *parent, unsigned int index,
+			 struct i2c_adapter **ppadapter);
 
-int lsdc_create_i2c_chan(struct drm_device *ddev,
-			 struct lsdc_display_pipe *dispipe,
-			 unsigned int index);
+int lsdc_i2c_preinit(struct device *parent);
 
 #endif
diff --git a/drivers/gpu/drm/loongson/lsdc_irq.c b/drivers/gpu/drm/loongson/lsdc_irq.c
index efdc4d10792d..c41b82a6e5cf 100644
--- a/drivers/gpu/drm/loongson/lsdc_irq.c
+++ b/drivers/gpu/drm/loongson/lsdc_irq.c
@@ -5,6 +5,7 @@
 
 #include <drm/drm_vblank.h>
 
+#include "loongson_module.h"
 #include "lsdc_irq.h"
 
 /*
@@ -35,11 +36,13 @@ irqreturn_t ls7a2000_dc_irq_handler(int irq, void *arg)
 	/* write "1" to clear the interrupt status */
 	lsdc_wreg32(ldev, LSDC_INT_REG, val);
 
-	if (ldev->irq_status & INT_CRTC0_VSYNC)
-		drm_handle_vblank(ddev, 0);
+	if (loongson_vblank) {
+		if (ldev->irq_status & INT_CRTC0_VSYNC)
+			drm_handle_vblank(ddev, 0);
 
-	if (ldev->irq_status & INT_CRTC1_VSYNC)
-		drm_handle_vblank(ddev, 1);
+		if (ldev->irq_status & INT_CRTC1_VSYNC)
+			drm_handle_vblank(ddev, 1);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -64,11 +67,13 @@ irqreturn_t ls7a1000_dc_irq_handler(int irq, void *arg)
 	val &= ~(INT_CRTC0_VSYNC | INT_CRTC1_VSYNC);
 	lsdc_wreg32(ldev, LSDC_INT_REG, val);
 
-	if (ldev->irq_status & INT_CRTC0_VSYNC)
-		drm_handle_vblank(ddev, 0);
+	if (loongson_vblank) {
+		if (ldev->irq_status & INT_CRTC0_VSYNC)
+			drm_handle_vblank(ddev, 0);
 
-	if (ldev->irq_status & INT_CRTC1_VSYNC)
-		drm_handle_vblank(ddev, 1);
+		if (ldev->irq_status & INT_CRTC1_VSYNC)
+			drm_handle_vblank(ddev, 1);
+	}
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/gpu/drm/loongson/lsdc_output.c b/drivers/gpu/drm/loongson/lsdc_output.c
new file mode 100644
index 000000000000..d5ae032d30d1
--- /dev/null
+++ b/drivers/gpu/drm/loongson/lsdc_output.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Authors:
+ *      Sui Jingfeng <sui.jingfeng@linux.dev>
+ */
+
+#include <linux/delay.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "lsdc_drv.h"
+#include "lsdc_output.h"
+
+static struct platform_device *lsdc_output_agent[LSDC_NUM_CRTC];
+
+void lsdc_output_match_add(struct device *master,
+			   struct component_match **matchptr)
+{
+	unsigned int i;
+
+	for (i = 0; i < LSDC_NUM_CRTC; ++i) {
+		if (!lsdc_output_agent[i])
+			continue;
+
+		component_match_add(master, matchptr, component_compare_dev,
+				    &lsdc_output_agent[i]->dev);
+	}
+}
+
+static struct property_entry ls7a1000_output_port_properties[LSDC_NUM_CRTC][3] = {
+	{
+		PROPERTY_ENTRY_STRING("type", "DVO"),
+		PROPERTY_ENTRY_U32("reg", 0),
+		{ },
+	},
+	{
+		PROPERTY_ENTRY_STRING("type", "DVO"),
+		PROPERTY_ENTRY_U32("reg", 1),
+		{ },
+	},
+};
+
+static struct property_entry ls7a2000_output_port_properties[LSDC_NUM_CRTC][3] = {
+	{
+		PROPERTY_ENTRY_STRING("type", "HDMI-or-VGA"),
+		PROPERTY_ENTRY_U32("reg", 0),
+		{ },
+	},
+	{
+		PROPERTY_ENTRY_STRING("type", "HDMI"),
+		PROPERTY_ENTRY_U32("reg", 1),
+		{ },
+	},
+};
+
+static struct property_entry *
+lsdc_output_get_property_entry(const struct lsdc_desc *descp,
+			       unsigned int index)
+{
+	if (index >= LSDC_NUM_CRTC)
+		goto idx_err_out;
+
+	switch (to_loongson_gfx(descp)->chip_id) {
+	case CHIP_LS7A1000:
+		return &ls7a1000_output_port_properties[index][0];
+	case CHIP_LS7A2000:
+		return &ls7a2000_output_port_properties[index][0];
+	default:
+		break;
+	};
+
+idx_err_out:
+	return ERR_PTR(-ENODEV);
+}
+
+static void lsdc_output_postfini(void *data)
+{
+	struct platform_device *agent = data;
+
+	platform_device_unregister(agent);
+}
+
+int lsdc_output_preinit(struct device *parent, const struct lsdc_desc *descp)
+{
+	unsigned int i;
+
+	for (i = 0; i < descp->num_of_crtc; ++i) {
+		struct platform_device_info devinfo = {};
+		struct platform_device *agent;
+		int ret;
+
+		devinfo.parent = parent;
+		devinfo.name = "lsdc-output";
+		devinfo.id = i;
+		devinfo.properties = lsdc_output_get_property_entry(descp, i);
+
+		agent = platform_device_register_full(&devinfo);
+		if (IS_ERR(agent)) {
+			dev_err(parent, "failed to register output agent\n");
+			return PTR_ERR(agent);
+		}
+
+		ret = devm_add_action_or_reset(parent, lsdc_output_postfini, agent);
+		if (ret)
+			return ret;
+
+		lsdc_output_agent[i] = agent;
+	}
+
+	return 0;
+}
+
+/*
+ * @dev: pointer to the port@0 or port@1 of the display output
+ * @master: pointer to the component master
+ * @data: pointer to the drm device control structure
+ */
+static int lsdc_output_bind(struct device *dev,
+			    struct device *master,
+			    void *data)
+{
+	struct drm_device *drm = data;
+	struct lsdc_device *ldev = to_lsdc(drm);
+	const struct lsdc_kms_funcs *kms_funcs = ldev->descp->funcs;
+	struct lsdc_output *output = dev_get_drvdata(dev);
+	unsigned int pipe = output->pipe;
+	int ret;
+
+	ret = kms_funcs->output_init(drm, output, ldev->i2c[pipe], pipe);
+	if (ret)
+		return ret;
+
+	ldev->dispipe[pipe].output = output;
+	ldev->num_output++;
+
+	return 0;
+}
+
+static void lsdc_output_unbind(struct device *dev,
+			       struct device *master,
+			       void *data)
+{
+	struct drm_device *drm = data;
+	struct lsdc_device *ldev = to_lsdc(drm);
+	struct lsdc_output *output = dev_get_drvdata(dev);
+	unsigned int pipe = output->pipe;
+
+	ldev->dispipe[pipe].output = NULL;
+}
+
+static const struct component_ops lsdc_output_component_ops = {
+	.bind = lsdc_output_bind,
+	.unbind = lsdc_output_unbind,
+};
+
+static void lsdc_output_destroy(void *data)
+{
+	struct lsdc_output *output = (struct lsdc_output *)data;
+
+	kfree(output);
+}
+
+static int lsdc_output_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device *parent = dev->parent;
+	struct lsdc_output *output;
+	const char *type;
+	int ret;
+
+	output = kzalloc(sizeof(*output), GFP_KERNEL);
+	if (!output)
+		return -ENOMEM;
+
+	ret = device_property_read_u32(dev, "reg", &output->pipe);
+	if (ret)
+		return ret;
+
+	ret = device_property_read_string(dev, "type", &type);
+	if (ret)
+		return ret;
+
+	output->dev = dev;
+	dev_set_drvdata(dev, output);
+
+	ret = devm_add_action_or_reset(parent, lsdc_output_destroy, output);
+	if (ret)
+		return ret;
+
+	dev_info(parent, "%s probed, type: %s\n", dev_name(dev), type);
+
+	return component_add(dev, &lsdc_output_component_ops);
+}
+
+static void lsdc_output_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &lsdc_output_component_ops);
+}
+
+struct platform_driver lsdc_output_platform_driver = {
+	.driver = {
+		.name = "lsdc-output",
+	},
+	.probe = lsdc_output_probe,
+	.remove_new = lsdc_output_remove,
+};
diff --git a/drivers/gpu/drm/loongson/lsdc_output.h b/drivers/gpu/drm/loongson/lsdc_output.h
index 097789051a1d..c7f0933695af 100644
--- a/drivers/gpu/drm/loongson/lsdc_output.h
+++ b/drivers/gpu/drm/loongson/lsdc_output.h
@@ -6,16 +6,46 @@
 #ifndef __LSDC_OUTPUT_H__
 #define __LSDC_OUTPUT_H__
 
-#include "lsdc_drv.h"
+#include <linux/component.h>
+
+#include <drm/drm_encoder.h>
+#include <drm/drm_connector.h>
+
+struct lsdc_desc;
+
+struct lsdc_output {
+	struct device *dev;
+	struct drm_encoder encoder;
+	struct drm_connector connector;
+	unsigned int pipe;
+};
+
+static inline struct lsdc_output *
+connector_to_lsdc_output(struct drm_connector *connector)
+{
+	return container_of(connector, struct lsdc_output, connector);
+}
+
+static inline struct lsdc_output *
+encoder_to_lsdc_output(struct drm_encoder *encoder)
+{
+	return container_of(encoder, struct lsdc_output, encoder);
+}
 
 int ls7a1000_output_init(struct drm_device *ddev,
-			 struct lsdc_display_pipe *dispipe,
+			 struct lsdc_output *output,
 			 struct i2c_adapter *ddc,
 			 unsigned int index);
 
 int ls7a2000_output_init(struct drm_device *ldev,
-			 struct lsdc_display_pipe *dispipe,
+			 struct lsdc_output *output,
 			 struct i2c_adapter *ddc,
 			 unsigned int index);
 
+int lsdc_output_preinit(struct device *parent,
+			const struct lsdc_desc *descp);
+
+void lsdc_output_match_add(struct device *parent,
+			   struct component_match **matchptr);
+
 #endif
diff --git a/drivers/gpu/drm/loongson/lsdc_output_7a1000.c b/drivers/gpu/drm/loongson/lsdc_output_7a1000.c
index 6fc8dd1c7d9a..edb78a19949f 100644
--- a/drivers/gpu/drm/loongson/lsdc_output_7a1000.c
+++ b/drivers/gpu/drm/loongson/lsdc_output_7a1000.c
@@ -3,6 +3,8 @@
  * Copyright (C) 2023 Loongson Technology Corporation Limited
  */
 
+#include <linux/property.h>
+
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_probe_helper.h>
@@ -140,11 +142,10 @@ static const struct drm_encoder_funcs ls7a1000_encoder_funcs[2] = {
 };
 
 int ls7a1000_output_init(struct drm_device *ddev,
-			 struct lsdc_display_pipe *dispipe,
+			 struct lsdc_output *output,
 			 struct i2c_adapter *ddc,
 			 unsigned int index)
 {
-	struct lsdc_output *output = &dispipe->output;
 	struct drm_encoder *encoder = &output->encoder;
 	struct drm_connector *connector = &output->connector;
 	int ret;
@@ -162,8 +163,6 @@ int ls7a1000_output_init(struct drm_device *ddev,
 	if (ret)
 		return ret;
 
-	drm_info(ddev, "display pipe-%u has a DVO\n", index);
-
 	drm_connector_helper_add(connector, &ls7a1000_dpi_connector_helpers);
 
 	drm_connector_attach_encoder(connector, encoder);
diff --git a/drivers/gpu/drm/loongson/lsdc_output_7a2000.c b/drivers/gpu/drm/loongson/lsdc_output_7a2000.c
index ce3dabec887e..c0e18cf85f5b 100644
--- a/drivers/gpu/drm/loongson/lsdc_output_7a2000.c
+++ b/drivers/gpu/drm/loongson/lsdc_output_7a2000.c
@@ -284,8 +284,7 @@ static int ls7a2000_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
 					   struct drm_display_mode *mode)
 {
 	struct lsdc_output *output = encoder_to_lsdc_output(encoder);
-	struct lsdc_display_pipe *dispipe = output_to_display_pipe(output);
-	unsigned int index = dispipe->index;
+	unsigned int index = output->pipe;
 	struct drm_device *ddev = encoder->dev;
 	struct lsdc_device *ldev = to_lsdc(ddev);
 	struct hdmi_avi_infoframe infoframe;
@@ -335,8 +334,7 @@ static void ls7a2000_hdmi_atomic_disable(struct drm_encoder *encoder,
 					 struct drm_atomic_state *state)
 {
 	struct lsdc_output *output = encoder_to_lsdc_output(encoder);
-	struct lsdc_display_pipe *dispipe = output_to_display_pipe(output);
-	unsigned int index = dispipe->index;
+	unsigned int index = output->pipe;
 	struct drm_device *ddev = encoder->dev;
 	struct lsdc_device *ldev = to_lsdc(ddev);
 	u32 val;
@@ -360,8 +358,7 @@ static void ls7a2000_hdmi_atomic_enable(struct drm_encoder *encoder,
 	struct drm_device *ddev = encoder->dev;
 	struct lsdc_device *ldev = to_lsdc(ddev);
 	struct lsdc_output *output = encoder_to_lsdc_output(encoder);
-	struct lsdc_display_pipe *dispipe = output_to_display_pipe(output);
-	unsigned int index = dispipe->index;
+	unsigned int index = output->pipe;
 	u32 val;
 
 	/* datasheet say it should larger than 48 */
@@ -482,8 +479,7 @@ static void ls7a2000_hdmi_atomic_mode_set(struct drm_encoder *encoder,
 					  struct drm_connector_state *conn_state)
 {
 	struct lsdc_output *output = encoder_to_lsdc_output(encoder);
-	struct lsdc_display_pipe *dispipe = output_to_display_pipe(output);
-	unsigned int index = dispipe->index;
+	unsigned int index = output->pipe;
 	struct drm_device *ddev = encoder->dev;
 	struct lsdc_device *ldev = to_lsdc(ddev);
 	struct drm_display_mode *mode = &crtc_state->mode;
@@ -512,11 +508,10 @@ static const struct drm_encoder_helper_funcs ls7a2000_encoder_helper_funcs = {
  * writing hdmi register do no harms.
  */
 int ls7a2000_output_init(struct drm_device *ddev,
-			 struct lsdc_display_pipe *dispipe,
+			 struct lsdc_output *output,
 			 struct i2c_adapter *ddc,
 			 unsigned int pipe)
 {
-	struct lsdc_output *output = &dispipe->output;
 	struct drm_encoder *encoder = &output->encoder;
 	struct drm_connector *connector = &output->connector;
 	int ret;
@@ -536,8 +531,6 @@ int ls7a2000_output_init(struct drm_device *ddev,
 	if (ret)
 		return ret;
 
-	drm_info(ddev, "display pipe-%u has HDMI %s\n", pipe, pipe ? "" : "and/or VGA");
-
 	drm_connector_helper_add(connector, &ls7a2000_connector_helpers);
 
 	drm_connector_attach_encoder(connector, encoder);
diff --git a/drivers/gpu/drm/loongson/lsdc_ttm.c b/drivers/gpu/drm/loongson/lsdc_ttm.c
index 465f622ac05d..72f51993d678 100644
--- a/drivers/gpu/drm/loongson/lsdc_ttm.c
+++ b/drivers/gpu/drm/loongson/lsdc_ttm.c
@@ -539,9 +539,9 @@ static void lsdc_ttm_fini(struct drm_device *ddev, void *data)
 	drm_dbg(ddev, "ttm finished\n");
 }
 
-int lsdc_ttm_init(struct lsdc_device *ldev)
+int lsdc_ttm_init(struct drm_device *ddev)
 {
-	struct drm_device *ddev = &ldev->base;
+	struct lsdc_device *ldev = to_lsdc(ddev);
 	unsigned long num_vram_pages;
 	unsigned long num_gtt_pages;
 	int ret;
diff --git a/drivers/gpu/drm/loongson/lsdc_ttm.h b/drivers/gpu/drm/loongson/lsdc_ttm.h
index 843e1475064e..064cf497e090 100644
--- a/drivers/gpu/drm/loongson/lsdc_ttm.h
+++ b/drivers/gpu/drm/loongson/lsdc_ttm.h
@@ -93,7 +93,7 @@ void lsdc_bo_clear(struct lsdc_bo *lbo);
 
 int lsdc_bo_evict_vram(struct drm_device *ddev);
 
-int lsdc_ttm_init(struct lsdc_device *ldev);
+int lsdc_ttm_init(struct drm_device *ddev);
 void lsdc_ttm_debugfs_init(struct lsdc_device *ldev);
 
 #endif
