diff --git a/drivers/gpu/drm/loongson/Makefile b/drivers/gpu/drm/loongson/Makefile
index 91e72bd900c1..d6e709e19fba 100644
--- a/drivers/gpu/drm/loongson/Makefile
+++ b/drivers/gpu/drm/loongson/Makefile
@@ -7,6 +7,7 @@ loongson-y := \
 	lsdc_drv.o \
 	lsdc_gem.o \
 	lsdc_gfxpll.o \
+	lsdc_gfxpll_2k1000.o \
 	lsdc_i2c.o \
 	lsdc_irq.o \
 	lsdc_output_7a1000.o \
diff --git a/drivers/gpu/drm/loongson/loongson_device.c b/drivers/gpu/drm/loongson/loongson_device.c
index 9986c8a2a255..67274d9e3b12 100644
--- a/drivers/gpu/drm/loongson/loongson_device.c
+++ b/drivers/gpu/drm/loongson/loongson_device.c
@@ -6,6 +6,7 @@
 #include <linux/pci.h>
 
 #include "lsdc_drv.h"
+#include "lsdc_probe.h"
 
 static const struct lsdc_kms_funcs ls7a1000_kms_funcs = {
 	.create_i2c = lsdc_create_i2c_chan,
@@ -25,6 +26,20 @@ static const struct lsdc_kms_funcs ls7a2000_kms_funcs = {
 	.crtc_init = ls7a2000_crtc_init,
 };
 
+/*
+ * Most of hardware features of ls2k1000 are same with ls7a1000, we take the
+ * ls7a1000_kms_funcs as a prototype, copy and modify to form a variant for
+ * ls2k1000.
+ */
+static const struct lsdc_kms_funcs ls2k1000_kms_funcs = {
+	.create_i2c = ls2k1000_get_i2c,
+	.irq_handler = ls7a1000_dc_irq_handler,
+	.output_init = ls7a1000_output_init,
+	.cursor_plane_init = ls7a1000_cursor_plane_init,
+	.primary_plane_init = lsdc_primary_plane_init,
+	.crtc_init = ls7a1000_crtc_init,
+};
+
 static const struct loongson_gfx_desc ls7a1000_gfx = {
 	.dc = {
 		.num_of_crtc = 2,
@@ -36,6 +51,7 @@ static const struct loongson_gfx_desc ls7a1000_gfx = {
 		.hw_cursor_h = 32,
 		.pitch_align = 256,
 		.has_vblank_counter = false,
+		.has_dedicated_vram = true,
 		.funcs = &ls7a1000_kms_funcs,
 	},
 	.conf_reg_base = LS7A1000_CONF_REG_BASE,
@@ -43,6 +59,7 @@ static const struct loongson_gfx_desc ls7a1000_gfx = {
 		.reg_offset = LS7A1000_PLL_GFX_REG,
 		.reg_size = 8,
 	},
+	.gfxpll_funcs = &ls7a1000_gfx_pll_funcs,
 	.pixpll = {
 		[0] = {
 			.reg_offset = LS7A1000_PIXPLL0_REG,
@@ -53,6 +70,7 @@ static const struct loongson_gfx_desc ls7a1000_gfx = {
 			.reg_size = 8,
 		},
 	},
+	.pixpll_funcs = &ls7a1000_pixpll_funcs,
 	.chip_id = CHIP_LS7A1000,
 	.model = "LS7A1000 bridge chipset",
 };
@@ -68,6 +86,7 @@ static const struct loongson_gfx_desc ls7a2000_gfx = {
 		.hw_cursor_h = 64,
 		.pitch_align = 64,
 		.has_vblank_counter = true,
+		.has_dedicated_vram = true,
 		.funcs = &ls7a2000_kms_funcs,
 	},
 	.conf_reg_base = LS7A2000_CONF_REG_BASE,
@@ -75,6 +94,7 @@ static const struct loongson_gfx_desc ls7a2000_gfx = {
 		.reg_offset = LS7A2000_PLL_GFX_REG,
 		.reg_size = 8,
 	},
+	.gfxpll_funcs = &ls7a2000_gfx_pll_funcs,
 	.pixpll = {
 		[0] = {
 			.reg_offset = LS7A2000_PIXPLL0_REG,
@@ -85,18 +105,57 @@ static const struct loongson_gfx_desc ls7a2000_gfx = {
 			.reg_size = 8,
 		},
 	},
+	.pixpll_funcs = &ls7a2000_pixpll_funcs,
 	.chip_id = CHIP_LS7A2000,
 	.model = "LS7A2000 bridge chipset",
 };
 
+static const struct loongson_gfx_desc ls2k1000_gfx = {
+	.dc = {
+		.num_of_crtc = 2,
+		.max_pixel_clk = 200000,
+		.max_width = 2048,
+		.max_height = 2048,
+		.num_of_hw_cursor = 1,
+		.hw_cursor_w = 32,
+		.hw_cursor_h = 32,
+		.pitch_align = 256,
+		.has_vblank_counter = false,
+		.has_dedicated_vram = false,
+		.funcs = &ls2k1000_kms_funcs,
+	},
+	.conf_reg_base = LS2K1000_CONF_REG_BASE,
+	.gfxpll = {
+		.reg_offset = LS2K1000_DDR_PLL_REG,
+		.reg_size = 16 + 16,
+	},
+	.gfxpll_funcs = &ls2k1000_gfx_pll_funcs,
+	.pixpll = {
+		[0] = {
+			.reg_offset = LS2K1000_PIX0_PLL_REG,
+			.reg_size = 16,
+		},
+		[1] = {
+			.reg_offset = LS2K1000_PIX1_PLL_REG,
+			.reg_size = 16,
+		},
+	},
+	.pixpll_funcs = &ls2k1000_pixpll_funcs,
+	.chip_id = CHIP_LS2K1000,
+	.model = "LS2K1000 SoC",
+};
+
 static const struct lsdc_desc *__chip_id_desc_table[] = {
 	[CHIP_LS7A1000] = &ls7a1000_gfx.dc,
 	[CHIP_LS7A2000] = &ls7a2000_gfx.dc,
+	[CHIP_LS2K1000] = &ls2k1000_gfx.dc,
 	[CHIP_LS_LAST] = NULL,
 };
 
 const struct lsdc_desc *
 lsdc_device_probe(struct pci_dev *pdev, enum loongson_chip_id chip_id)
 {
+	chip_id = loongson_chip_id_fixup(chip_id);
+
 	return __chip_id_desc_table[chip_id];
 }
diff --git a/drivers/gpu/drm/loongson/lsdc_drv.c b/drivers/gpu/drm/loongson/lsdc_drv.c
index 89ccc0c43169..65a4d96448bb 100644
--- a/drivers/gpu/drm/loongson/lsdc_drv.c
+++ b/drivers/gpu/drm/loongson/lsdc_drv.c
@@ -5,6 +5,7 @@
 
 #include <linux/pci.h>
 #include <linux/vgaarb.h>
+#include <linux/of_address.h>
 
 #include <drm/drm_aperture.h>
 #include <drm/drm_atomic.h>
@@ -84,6 +85,8 @@ static int lsdc_modeset_init(struct lsdc_device *ldev,
 		dispipe = &ldev->dispipe[i];
 		if (dispipe->li2c)
 			ddc = &dispipe->li2c->adapter;
+		else
+			ddc = dispipe->adapter;
 
 		ret = funcs->output_init(ddev, dispipe, ddc, i);
 		if (ret)
@@ -155,8 +158,7 @@ static int lsdc_mode_config_init(struct drm_device *ddev,
  * the DC could access the on-board VRAM.
  */
 static int lsdc_get_dedicated_vram(struct lsdc_device *ldev,
-				   struct pci_dev *pdev_dc,
-				   const struct lsdc_desc *descp)
+				   struct pci_dev *pdev_dc)
 {
 	struct drm_device *ddev = &ldev->base;
 	struct pci_dev *pdev_gpu;
@@ -187,6 +189,38 @@ static int lsdc_get_dedicated_vram(struct lsdc_device *ldev,
 	return 0;
 }
 
+static int lsdc_of_get_reserved_mem(struct lsdc_device *ldev)
+{
+	struct drm_device *ddev = &ldev->base;
+	unsigned long size = 0;
+	struct device_node *node;
+	struct resource r;
+	int ret;
+
+	if (!ddev->dev->of_node)
+		return -ENOENT;
+
+	node = of_parse_phandle(ddev->dev->of_node, "memory-region", 0);
+	if (!node) {
+		drm_err(ddev, "No memory-region property\n");
+		return -ENOENT;
+	}
+
+	ret = of_address_to_resource(node, 0, &r);
+	of_node_put(node);
+	if (ret)
+		return ret;
+
+	size = r.end - r.start + 1;
+
+	ldev->vram_base = r.start;
+	ldev->vram_size = size;
+
+	drm_info(ddev, "Using of reserved mem: %lx@%pa\n", size, &r.start);
+
+	return 0;
+}
+
 static struct lsdc_device *
 lsdc_create_device(struct pci_dev *pdev,
 		   const struct lsdc_desc *descp,
@@ -207,7 +241,11 @@ lsdc_create_device(struct pci_dev *pdev,
 
 	loongson_gfxpll_create(ddev, &ldev->gfxpll);
 
-	ret = lsdc_get_dedicated_vram(ldev, pdev, descp);
+	if (descp->has_dedicated_vram)
+		ret = lsdc_get_dedicated_vram(ldev, pdev);
+	else
+		ret = lsdc_of_get_reserved_mem(ldev);
+
 	if (ret) {
 		drm_err(ddev, "Init VRAM failed: %d\n", ret);
 		return ERR_PTR(ret);
diff --git a/drivers/gpu/drm/loongson/lsdc_drv.h b/drivers/gpu/drm/loongson/lsdc_drv.h
index fbf2d760ef27..279de7bf6dc5 100644
--- a/drivers/gpu/drm/loongson/lsdc_drv.h
+++ b/drivers/gpu/drm/loongson/lsdc_drv.h
@@ -41,6 +41,7 @@
 enum loongson_chip_id {
 	CHIP_LS7A1000 = 0,
 	CHIP_LS7A2000 = 1,
+	CHIP_LS2K1000 = 2,
 	CHIP_LS_LAST,
 };
 
@@ -61,6 +62,7 @@ struct lsdc_desc {
 	u32 hw_cursor_h;
 	u32 pitch_align;         /* CRTC DMA alignment constraint */
 	bool has_vblank_counter; /* 32 bit hw vsync counter */
+	bool has_dedicated_vram;
 
 	/* device dependent ops, dc side */
 	const struct lsdc_kms_funcs *funcs;
@@ -78,12 +80,14 @@ struct loongson_gfx_desc {
 		u32 reg_offset;
 		u32 reg_size;
 	} gfxpll;
+	const struct loongson_gfxpll_funcs *gfxpll_funcs;
 
 	/* Pixel PLL, per display pipe */
 	struct {
 		u32 reg_offset;
 		u32 reg_size;
 	} pixpll[LSDC_NUM_CRTC];
+	const struct lsdc_pixpll_funcs *pixpll_funcs;
 
 	enum loongson_chip_id chip_id;
 	char model[64];
@@ -189,6 +193,11 @@ struct lsdc_display_pipe {
 	struct lsdc_primary primary;
 	struct lsdc_cursor cursor;
 	struct lsdc_output output;
+	/*
+	 * For device which don't has built-in GPIO hardware, such as ls2k1000,
+	 * we will get a i2c adapter from other module or subsystem.
+	 */
+	struct i2c_adapter *adapter;
 	struct lsdc_i2c *li2c;
 	unsigned int index;
 };
diff --git a/drivers/gpu/drm/loongson/lsdc_gfxpll.c b/drivers/gpu/drm/loongson/lsdc_gfxpll.c
index 249c09d703ad..4a4efe696d5a 100644
--- a/drivers/gpu/drm/loongson/lsdc_gfxpll.c
+++ b/drivers/gpu/drm/loongson/lsdc_gfxpll.c
@@ -163,7 +163,14 @@ static int loongson_gfxpll_init(struct loongson_gfxpll * const this)
 	return 0;
 }
 
-static const struct loongson_gfxpll_funcs lsdc_gmc_gpu_funcs = {
+const struct loongson_gfxpll_funcs ls7a1000_gfx_pll_funcs = {
+	.init = loongson_gfxpll_init,
+	.update = loongson_gfxpll_update,
+	.get_rates = loongson_gfxpll_get_rates,
+	.print = loongson_gfxpll_print,
+};
+
+const struct loongson_gfxpll_funcs ls7a2000_gfx_pll_funcs = {
 	.init = loongson_gfxpll_init,
 	.update = loongson_gfxpll_update,
 	.get_rates = loongson_gfxpll_get_rates,
@@ -185,7 +192,7 @@ int loongson_gfxpll_create(struct drm_device *ddev,
 	this->ddev = ddev;
 	this->reg_size = gfx->gfxpll.reg_size;
 	this->reg_base = gfx->conf_reg_base + gfx->gfxpll.reg_offset;
-	this->funcs = &lsdc_gmc_gpu_funcs;
+	this->funcs = gfx->gfxpll_funcs;
 
 	ret = this->funcs->init(this);
 	if (unlikely(ret)) {
diff --git a/drivers/gpu/drm/loongson/lsdc_gfxpll.h b/drivers/gpu/drm/loongson/lsdc_gfxpll.h
index 9d59cbfc145d..6a30d2039d4a 100644
--- a/drivers/gpu/drm/loongson/lsdc_gfxpll.h
+++ b/drivers/gpu/drm/loongson/lsdc_gfxpll.h
@@ -49,4 +49,8 @@ struct loongson_gfxpll {
 int loongson_gfxpll_create(struct drm_device *ddev,
 			   struct loongson_gfxpll **ppout);
 
+extern const struct loongson_gfxpll_funcs ls2k1000_gfx_pll_funcs;
+extern const struct loongson_gfxpll_funcs ls7a1000_gfx_pll_funcs;
+extern const struct loongson_gfxpll_funcs ls7a2000_gfx_pll_funcs;
+
 #endif
diff --git a/drivers/gpu/drm/loongson/lsdc_gfxpll_2k1000.c b/drivers/gpu/drm/loongson/lsdc_gfxpll_2k1000.c
new file mode 100644
index 000000000000..8b442db05972
--- /dev/null
+++ b/drivers/gpu/drm/loongson/lsdc_gfxpll_2k1000.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 Loongson Technology Corporation Limited
+ */
+
+#include <linux/delay.h>
+
+#include <drm/drm_file.h>
+#include <drm/drm_managed.h>
+#include <drm/drm_print.h>
+
+#include "lsdc_drv.h"
+
+union ls2k1000_ddr_pll_reg_bitmap {
+	struct ls2k1000_ddr_pll_bitmap {
+		/* Byte 0 ~ Byte 3 */
+		unsigned bypass       :  1;  /*  0: Bypass ddr pll entirely */
+		unsigned oe_gpu       :  1;  /*  1: GPU output clk enable   */
+		unsigned write_en     :  1;  /*  2: Allow software update   */
+		unsigned _reserved_1_ : 23;  /*  3 : 25  Don't care         */
+		unsigned div_ref      :  6;  /* 31 : 26  Input clk divider  */
+		/* Byte 4 ~ Byte 7 */
+		unsigned loopc        : 10;   /* 41 : 32 Clock multiplier   */
+		unsigned _reserved_2_ : 22;   /* 42 : 63 Useless            */
+
+		/* Byte 8 ~ Byte 15 */
+		unsigned div_out_ddr  :  6;  /*  5 : 0  DDR output divider */
+		unsigned _reserved_3_ : 16;  /* 21 : 6  */
+		unsigned div_out_gpu  :  6;  /* 27 : 22 GPU output divider */
+		unsigned _reserved_4_ : 16;  /* 43 : 28 */
+		unsigned div_out_hda  :  7;  /* 50 : 44 HDA output divider */
+		unsigned _reserved_5_ : 13;  /* 63 : 51 */
+	} bitmap;
+	u32 w[4];
+	u64 d[2];
+};
+
+union ls2k1000_dc_pll_reg_bitmap {
+	struct ls2k1000_dc_pll_bitmap {
+		/* Byte 0 ~ Byte 3 */
+		unsigned _reserved_1_ : 26;  /*  0 : 25  Don't care         */
+		unsigned div_ref      :  6;  /* 31 : 26  Input clk divider  */
+		/* Byte 4 ~ Byte 7 */
+		unsigned loopc        : 10;   /* 41 : 32 Clock multiplier   */
+		unsigned _reserved_2_ : 22;   /* 42 : 63 Useless            */
+
+		/* Byte 8 ~ Byte 15 */
+		unsigned div_out_dc   :  6;  /*  5 : 0  DC output divider */
+		unsigned _reserved_3_ : 16;  /* 21 : 6  */
+		unsigned div_out_gmac :  6;  /* 27 : 22 GMAC output divider */
+		unsigned _reserved_4_ :  4;  /* 31 : 28 */
+		unsigned _reserved_5_ : 32;  /* 63 : 32 */
+	} bitmap;
+	u32 w[4];
+	u64 d[2];
+};
+
+static int ls2k1000_gfxpll_init(struct loongson_gfxpll * const this)
+{
+	struct drm_printer printer = drm_info_printer(this->ddev->dev);
+
+	this->mmio = ioremap(this->reg_base, this->reg_size);
+	if (IS_ERR_OR_NULL(this->mmio))
+		return -ENOMEM;
+
+	this->funcs->print(this, &printer, false);
+
+	return 0;
+}
+
+static inline void __rreg_u128(void __iomem *mmio, u32 w[], u64 d[])
+{
+#if defined(CONFIG_64BIT)
+	d[0] = readq(mmio);
+	d[1] = readq(mmio + 8);
+#else
+	w[0] = readl(mmio);
+	w[1] = readl(mmio + 4);
+	w[2] = readl(mmio + 8);
+	w[3] = readl(mmio + 12);
+#endif
+}
+
+static void ls2k1000_gfxpll_get_rates(struct loongson_gfxpll * const this,
+				      unsigned int *dc,
+				      unsigned int *ddr,
+				      unsigned int *gpu)
+{
+	unsigned int ref_clock_mhz = LSDC_PLL_REF_CLK_KHZ / 1000;
+	union ls2k1000_ddr_pll_reg_bitmap ddr_pll_reg_bitmap;
+	union ls2k1000_dc_pll_reg_bitmap dc_pll_reg_bitmap;
+	unsigned int div_ref;
+	unsigned int loopc;
+	unsigned int div_out_dc;
+	unsigned int div_out_ddr;
+	unsigned int div_out_gpu;
+	unsigned int dc_mhz;
+	unsigned int ddr_mhz;
+	unsigned int gpu_mhz;
+
+	__rreg_u128(this->mmio, ddr_pll_reg_bitmap.w, ddr_pll_reg_bitmap.d);
+	div_ref = ddr_pll_reg_bitmap.bitmap.div_ref;
+	loopc = ddr_pll_reg_bitmap.bitmap.loopc;
+	div_out_ddr = ddr_pll_reg_bitmap.bitmap.div_out_ddr;
+	div_out_gpu = ddr_pll_reg_bitmap.bitmap.div_out_gpu;
+	ddr_mhz = ref_clock_mhz / div_ref * loopc / div_out_ddr;
+	gpu_mhz = ref_clock_mhz / div_ref * loopc / div_out_gpu;
+
+	__rreg_u128(this->mmio + 16, dc_pll_reg_bitmap.w, dc_pll_reg_bitmap.d);
+	div_out_dc = dc_pll_reg_bitmap.bitmap.div_out_dc;
+	div_ref = dc_pll_reg_bitmap.bitmap.div_ref;
+	loopc = dc_pll_reg_bitmap.bitmap.loopc;
+	dc_mhz = ref_clock_mhz / div_ref * loopc / div_out_dc;
+
+	if (dc)
+		*dc = dc_mhz;
+
+	if (ddr)
+		*ddr = ddr_mhz;
+
+	if (gpu)
+		*gpu = gpu_mhz;
+}
+
+static void ls2k1000_gfxpll_print(struct loongson_gfxpll * const this,
+				  struct drm_printer *p,
+				  bool verbose)
+{
+	unsigned int dc, ddr, gpu;
+
+	this->funcs->get_rates(this, &dc, &ddr, &gpu);
+
+	drm_printf(p, "dc: %uMHz, ddr: %uMHz, gpu: %uMHz\n", dc, ddr, gpu);
+}
+
+const struct loongson_gfxpll_funcs ls2k1000_gfx_pll_funcs = {
+	.init = ls2k1000_gfxpll_init,
+	.get_rates = ls2k1000_gfxpll_get_rates,
+	.print = ls2k1000_gfxpll_print,
+};
+
diff --git a/drivers/gpu/drm/loongson/lsdc_i2c.c b/drivers/gpu/drm/loongson/lsdc_i2c.c
index 9625d0b1d0b4..726d434c6234 100644
--- a/drivers/gpu/drm/loongson/lsdc_i2c.c
+++ b/drivers/gpu/drm/loongson/lsdc_i2c.c
@@ -177,3 +177,44 @@ int lsdc_create_i2c_chan(struct drm_device *ddev,
 
 	return 0;
 }
+
+static void ls2k1000_put_i2c(struct drm_device *ddev, void *data)
+{
+	struct i2c_adapter *adapter = (struct i2c_adapter *)data;
+
+	if (adapter)
+		i2c_put_adapter(adapter);
+}
+
+int ls2k1000_get_i2c(struct drm_device *ddev,
+		     struct lsdc_display_pipe *dispipe,
+		     unsigned int index)
+{
+	struct i2c_adapter *adapter;
+	int ret;
+
+	/*
+	 * On ls2k1000, display-pipe-0 use i2c-0 and display-pipe-1 use i2c-1
+	 * by default. We will add more complete DT support for this in the
+	 * future.
+	 */
+	adapter = i2c_get_adapter(index);
+	if (!adapter) {
+		drm_dbg(ddev, "DDC drivers are not ready\n");
+		/*
+		 * Should return -EPROBE_DEFER here, but we want to do so when
+		 * the DT support is added. Current we are focus on bring up,
+		 * For embedded platform, the i2c adapter is not strictly
+		 * required to be able to display something on the screen.
+		 */
+		return 0;
+	}
+
+	ret = drmm_add_action_or_reset(ddev, ls2k1000_put_i2c, adapter);
+	if (ret)
+		return ret;
+
+	dispipe->adapter = adapter;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/loongson/lsdc_i2c.h b/drivers/gpu/drm/loongson/lsdc_i2c.h
index 88cd1a1817a5..97eb6227f386 100644
--- a/drivers/gpu/drm/loongson/lsdc_i2c.h
+++ b/drivers/gpu/drm/loongson/lsdc_i2c.h
@@ -26,4 +26,8 @@ int lsdc_create_i2c_chan(struct drm_device *ddev,
 			 struct lsdc_display_pipe *dispipe,
 			 unsigned int index);
 
+int ls2k1000_get_i2c(struct drm_device *ddev,
+		     struct lsdc_display_pipe *dispipe,
+		     unsigned int index);
+
 #endif
diff --git a/drivers/gpu/drm/loongson/lsdc_pixpll.c b/drivers/gpu/drm/loongson/lsdc_pixpll.c
index 2609a2256da4..28290dcd7534 100644
--- a/drivers/gpu/drm/loongson/lsdc_pixpll.c
+++ b/drivers/gpu/drm/loongson/lsdc_pixpll.c
@@ -41,6 +41,132 @@ union lsdc_pixpll_reg_bitmap {
 	u64 d;
 };
 
+/*
+ * The pixel PLL structure of ls2k1000 is defferent than ls7a2000/ls2k2000.
+ * it take up 16 bytes, but only a few bits are useful. Sounds like a little
+ * bit of wasting register space, but this is the hardware already have been
+ * tapped.
+ */
+union ls2k1000_pixpll_reg_bitmap {
+	struct ls2k1000_pixpll_reg {
+		/* Byte 0 ~ Byte 3 */
+		unsigned sel_out      :  1;  /*  0    select this PLL        */
+		unsigned _reserved_1_ :  1;  /*  1                           */
+		unsigned sw_adj_en    :  1;  /*  2    allow software adjust  */
+		unsigned bypass       :  1;  /*  3    bypass L1 PLL          */
+		unsigned _reserved_2_ :  3;  /*  4:6                         */
+		unsigned lock_en      :  1;  /*  7    enable lock L1 PLL     */
+		unsigned _reserved_3_ :  2;  /*  8:9                         */
+		unsigned lock_check   :  2;  /* 10:11 precision check        */
+		unsigned _reserved_4_ :  4;  /* 12:15                        */
+
+		unsigned locked       :  1;  /* 16    PLL locked flag bit    */
+		unsigned _reserved_5_ :  2;  /* 17:18                        */
+		unsigned powerdown    :  1;  /* 19    powerdown the pll      */
+		unsigned _reserved_6_ :  6;  /* 20:25                        */
+		unsigned div_ref      :  6;  /* 26:31 L1 Prescaler           */
+
+		/* Byte 4 ~ Byte 7 */
+		unsigned loopc        : 10;  /* 32:41 Clock Multiplier       */
+		unsigned l1_div       :  6;  /* 42:47 no use                 */
+		unsigned _reserved_7_ : 16;  /* 48:63                        */
+
+		/* Byte 8 ~ Byte 15 */
+		unsigned div_out      :  6;  /* 64 : 69   output clk divider */
+		unsigned _reserved_8_ : 26;  /* 70 : 127  no use             */
+	} bitmap;
+
+	u32 w[4];
+	u64 d[2];
+};
+
+/*
+ * Update the pll parameters to hardware, target to the pixpll in ls2k1000
+ *
+ * @this: point to the object from which this function is called
+ * @pin: point to the struct of lsdc_pll_parms passed in
+ *
+ * return 0 if successful.
+ */
+static int ls2k1000_pixpll_param_update(struct lsdc_pixpll * const this,
+					struct lsdc_pixpll_parms const *pin)
+{
+	void __iomem *reg = this->mmio;
+	unsigned int counter = 0;
+	bool locked = false;
+	u32 val;
+
+	val = readl(reg);
+	/* Bypass the software configured PLL, using refclk directly */
+	val &= ~(1 << 0);
+	writel(val, reg);
+
+	/* Powerdown the PLL */
+	val |= (1 << 19);
+	writel(val, reg);
+
+	/* Allow the software configuration */
+	val &= ~(1 << 2);
+	writel(val, reg);
+
+	/* allow L1 PLL lock */
+	val = (1L << 7) | (3L << 10);
+	writel(val, reg);
+
+	/* clear div_ref bit field */
+	val &= ~(0x3f << 26);
+	/* set div_ref bit field */
+	val |= pin->div_ref << 26;
+	writel(val, reg);
+
+	val = readl(reg + 4);
+	/* clear loopc bit field */
+	val &= ~0x0fff;
+	/* set loopc bit field */
+	val |= pin->loopc;
+	writel(val, reg + 4);
+
+	/* set div_out */
+	writel(pin->div_out, reg + 8);
+
+	val = readl(reg);
+	/* use this parms configured just now */
+	val |= (1 << 2);
+	/* powerup the PLL */
+	val &= ~(1 << 19);
+	writel(val, reg);
+
+	/* wait pll setup and locked */
+	do {
+		val = readl(reg);
+		locked = val & 0x10000;
+		counter++;
+	} while (!locked && (counter < 2000));
+
+	drm_dbg(this->ddev, "%u loop waited\n", counter);
+
+	/* Switch to software configured PLL instead of refclk */
+	val |= 1;
+	writel(val, reg);
+
+	return 0;
+}
+
+static unsigned int
+ls2k1000_pixpll_get_clock_rate(struct lsdc_pixpll * const this)
+{
+	struct lsdc_pixpll_parms *ppar = this->priv;
+	union ls2k1000_pixpll_reg_bitmap reg_bitmap;
+	struct ls2k1000_pixpll_reg *obj = &reg_bitmap.bitmap;
+
+	reg_bitmap.w[0] = readl(this->mmio);
+	reg_bitmap.w[1] = readl(this->mmio + 4);
+	reg_bitmap.w[2] = readl(this->mmio + 8);
+	reg_bitmap.w[3] = readl(this->mmio + 12);
+
+	return ppar->ref_clock / obj->div_ref * obj->loopc / obj->div_out;
+}
+
 struct clk_to_pixpll_parms_lookup_t {
 	unsigned int clock;        /* kHz */
 
@@ -452,11 +578,19 @@ static void lsdc_pixpll_print(struct lsdc_pixpll * const this,
 }
 
 /*
- * LS7A1000, LS7A2000 and ls2k2000's pixel pll setting register is same,
+ * LS7A1000, LS7A2000 and LS2K2000's pixel PLL register layout is same,
  * we take this as default, create a new instance if a different model is
  * introduced.
  */
-static const struct lsdc_pixpll_funcs __pixpll_default_funcs = {
+const struct lsdc_pixpll_funcs ls7a1000_pixpll_funcs = {
+	.setup = lsdc_pixel_pll_setup,
+	.compute = lsdc_pixel_pll_compute,
+	.update = lsdc_pixpll_update,
+	.get_rate = lsdc_pixpll_get_freq,
+	.print = lsdc_pixpll_print,
+};
+
+const struct lsdc_pixpll_funcs ls7a2000_pixpll_funcs = {
 	.setup = lsdc_pixel_pll_setup,
 	.compute = lsdc_pixel_pll_compute,
 	.update = lsdc_pixpll_update,
@@ -464,6 +598,19 @@ static const struct lsdc_pixpll_funcs __pixpll_default_funcs = {
 	.print = lsdc_pixpll_print,
 };
 
+/*
+ * The bit fileds of LS2K1000's pixel PLL register are different from other
+ * model, due to hardware update(revision). So we introduce a new instance
+ * of lsdc_pixpll_funcs object function to gear the control.
+ */
+const struct lsdc_pixpll_funcs ls2k1000_pixpll_funcs = {
+	.setup = lsdc_pixel_pll_setup,
+	.compute = lsdc_pixel_pll_compute,
+	.update = ls2k1000_pixpll_param_update,
+	.get_rate = ls2k1000_pixpll_get_clock_rate,
+	.print = lsdc_pixpll_print,
+};
+
 /* pixel pll initialization */
 
 int lsdc_pixpll_init(struct lsdc_pixpll * const this,
@@ -477,7 +624,7 @@ int lsdc_pixpll_init(struct lsdc_pixpll * const this,
 	this->ddev = ddev;
 	this->reg_size = 8;
 	this->reg_base = gfx->conf_reg_base + gfx->pixpll[index].reg_offset;
-	this->funcs = &__pixpll_default_funcs;
+	this->funcs = gfx->pixpll_funcs;
 
 	return this->funcs->setup(this);
 }
diff --git a/drivers/gpu/drm/loongson/lsdc_pixpll.h b/drivers/gpu/drm/loongson/lsdc_pixpll.h
index ec3486d90ab6..8b6ffd0ef4fb 100644
--- a/drivers/gpu/drm/loongson/lsdc_pixpll.h
+++ b/drivers/gpu/drm/loongson/lsdc_pixpll.h
@@ -83,4 +83,8 @@ int lsdc_pixpll_init(struct lsdc_pixpll * const this,
 		     struct drm_device *ddev,
 		     unsigned int index);
 
+extern const struct lsdc_pixpll_funcs ls2k1000_pixpll_funcs;
+extern const struct lsdc_pixpll_funcs ls7a1000_pixpll_funcs;
+extern const struct lsdc_pixpll_funcs ls7a2000_pixpll_funcs;
+
 #endif
diff --git a/drivers/gpu/drm/loongson/lsdc_probe.c b/drivers/gpu/drm/loongson/lsdc_probe.c
index 48ba69bb8a98..edc3812f0957 100644
--- a/drivers/gpu/drm/loongson/lsdc_probe.c
+++ b/drivers/gpu/drm/loongson/lsdc_probe.c
@@ -54,3 +54,30 @@ unsigned int loongson_cpu_get_prid(u8 *imp, u8 *rev)
 
 	return prid;
 }
+
+enum loongson_chip_id loongson_chip_id_fixup(enum loongson_chip_id chip_id)
+{
+	u8 impl;
+
+	if (loongson_cpu_get_prid(&impl, NULL)) {
+		/*
+		 * LS2K1000 has the LoongArch edition(with two LA264 CPU core)
+		 * and the Mips edition(with two mips64r2 CPU core), Only the
+		 * instruction set of the CPU are changed, the peripheral
+		 * devices are basically same.
+		 */
+		if (chip_id == CHIP_LS7A1000) {
+#if defined(__loongarch__)
+			if (impl == LOONGARCH_CPU_IMP_LS2K1000)
+				return CHIP_LS2K1000;
+#endif
+
+#if defined(__mips__)
+			if (impl == LOONGSON_CPU_MIPS_IMP_LS2K)
+				return CHIP_LS2K1000;
+#endif
+		}
+	}
+
+	return chip_id;
+}
diff --git a/drivers/gpu/drm/loongson/lsdc_probe.h b/drivers/gpu/drm/loongson/lsdc_probe.h
index 8bb6de2e3c64..8c630c5c90ce 100644
--- a/drivers/gpu/drm/loongson/lsdc_probe.h
+++ b/drivers/gpu/drm/loongson/lsdc_probe.h
@@ -9,4 +9,6 @@
 /* Helpers for chip detection */
 unsigned int loongson_cpu_get_prid(u8 *impl, u8 *rev);
 
+enum loongson_chip_id loongson_chip_id_fixup(enum loongson_chip_id chip_id);
+
 #endif
diff --git a/drivers/gpu/drm/loongson/lsdc_regs.h b/drivers/gpu/drm/loongson/lsdc_regs.h
index e8ea28689c63..c11a9fc0d2f6 100644
--- a/drivers/gpu/drm/loongson/lsdc_regs.h
+++ b/drivers/gpu/drm/loongson/lsdc_regs.h
@@ -39,6 +39,42 @@
 
 #define LS7A2000_CONF_REG_BASE          0x10010000
 
+/*
+ * The display controller in LS2K1000 SoC is basically same with the display
+ * controller in LS7A1000, except that there no built-in gpio hardware unit
+ * and no dedicated VRAM.
+ *       ___________________                                     _________
+ *      |            -------|                                   |         |
+ *      |  CRTC0 --> | DVO0 ----> Encoder0 ---> Connector0 ---> | Display |
+ *      |  _   _     -------|        ^              ^           |_________|
+ *      | | | | |           |        |              |
+ *      | |_| |_|           |     +------+          |
+ *      |                   <---->| i2c0 |<---------+
+ *      |  DC in LS2K1000   |     +------+
+ *      |  _   _            |     +------+
+ *      | | | | |           <---->| i2c1 |----------+
+ *      | |_| |_|           |     +------+          |            _________
+ *      |            -------|        |              |           |         |
+ *      |  CRTC1 --> | DVO1 ----> Encoder1 ---> Connector1 ---> |  Panel  |
+ *      |            -------|                                   |_________|
+ *      |___________________|
+ *
+ */
+
+#if defined(__mips__)
+#define LS2K1000_CONF_REG_BASE           0x1fe10000    /* mips64r2 edition */
+#else
+#define LS2K1000_CONF_REG_BASE           0x1fe00000    /* LoongArch edition */
+#endif
+
+/* The HDA, GPU, DDR share the single DDR PLL */
+#define LS2K1000_DDR_PLL_REG             0x0490
+/* The DC and GMAC share the same PLL */
+#define LS2K1000_DC_PLL_REG              0x04A0
+
+#define LS2K1000_PIX0_PLL_REG            0x04B0
+#define LS2K1000_PIX1_PLL_REG            0x04C0
+
 /* For LSDC_CRTCx_CFG_REG */
 #define CFG_PIX_FMT_MASK                GENMASK(2, 0)
 
