Update Linux to v5.10.109

Sourced from [1]

[1] https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.109.tar.xz

Change-Id: I19bca9fc6762d4e63bcf3e4cba88bbe560d9c76c
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/arch/mips/loongson2ef/Kconfig b/arch/mips/loongson2ef/Kconfig
new file mode 100644
index 0000000..96dc6eb
--- /dev/null
+++ b/arch/mips/loongson2ef/Kconfig
@@ -0,0 +1,94 @@
+# SPDX-License-Identifier: GPL-2.0
+if MACH_LOONGSON2EF
+
+choice
+	prompt "Machine Type"
+
+config LEMOTE_FULOONG2E
+	bool "Lemote Fuloong(2e) mini-PC"
+	select ARCH_SPARSEMEM_ENABLE
+	select ARCH_MIGHT_HAVE_PC_PARPORT
+	select ARCH_MIGHT_HAVE_PC_SERIO
+	select CEVT_R4K
+	select CSRC_R4K
+	select SYS_HAS_CPU_LOONGSON2E
+	select DMA_NONCOHERENT
+	select BOOT_ELF32
+	select BOARD_SCACHE
+	select FORCE_PCI
+	select I8259
+	select ISA
+	select IRQ_MIPS_CPU
+	select SYS_SUPPORTS_64BIT_KERNEL
+	select SYS_SUPPORTS_LITTLE_ENDIAN
+	select SYS_SUPPORTS_HIGHMEM
+	select SYS_HAS_EARLY_PRINTK
+	select USE_GENERIC_EARLY_PRINTK_8250
+	select GENERIC_ISA_DMA_SUPPORT_BROKEN
+	select CPU_HAS_WB
+	select LOONGSON_MC146818
+	help
+	  Lemote Fuloong(2e) mini-PC board based on the Chinese Loongson-2E CPU and
+	  an FPGA northbridge
+
+	  Lemote Fuloong(2e) mini PC have a VIA686B south bridge.
+
+config LEMOTE_MACH2F
+	bool "Lemote Loongson 2F family machines"
+	select ARCH_SPARSEMEM_ENABLE
+	select ARCH_MIGHT_HAVE_PC_PARPORT
+	select ARCH_MIGHT_HAVE_PC_SERIO
+	select BOARD_SCACHE
+	select BOOT_ELF32
+	select CEVT_R4K if ! MIPS_EXTERNAL_TIMER
+	select CPU_HAS_WB
+	select CS5536
+	select CSRC_R4K if ! MIPS_EXTERNAL_TIMER
+	select DMA_NONCOHERENT
+	select GENERIC_ISA_DMA_SUPPORT_BROKEN
+	select FORCE_PCI
+	select I8259
+	select IRQ_MIPS_CPU
+	select ISA
+	select SYS_HAS_CPU_LOONGSON2F
+	select SYS_HAS_EARLY_PRINTK
+	select USE_GENERIC_EARLY_PRINTK_8250
+	select SYS_SUPPORTS_64BIT_KERNEL
+	select SYS_SUPPORTS_HIGHMEM
+	select SYS_SUPPORTS_LITTLE_ENDIAN
+	select LOONGSON_MC146818
+	help
+	  Lemote Loongson 2F family machines utilize the 2F revision of
+	  Loongson processor and the AMD CS5536 south bridge.
+
+	  These family machines include fuloong2f mini PC, yeeloong2f notebook,
+	  LingLoong allinone PC and so forth.
+
+endchoice
+
+config CS5536
+	bool
+
+config CS5536_MFGPT
+	bool "CS5536 MFGPT Timer"
+	depends on CS5536 && !HIGH_RES_TIMERS
+	select MIPS_EXTERNAL_TIMER
+	help
+	  This option enables the mfgpt0 timer of AMD CS5536. With this timer
+	  switched on you can not use high resolution timers.
+
+	  If you want to enable the Loongson2 CPUFreq Driver, Please enable
+	  this option at first, otherwise, You will get wrong system time.
+
+	  If unsure, say Yes.
+
+config LOONGSON_UART_BASE
+	bool
+	default y
+	depends on EARLY_PRINTK || SERIAL_8250
+
+config LOONGSON_MC146818
+	bool
+	default n
+
+endif # MACH_LOONGSON2EF
diff --git a/arch/mips/loongson2ef/Makefile b/arch/mips/loongson2ef/Makefile
new file mode 100644
index 0000000..d4af160
--- /dev/null
+++ b/arch/mips/loongson2ef/Makefile
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Common code for all Loongson based systems
+#
+
+obj-$(CONFIG_MACH_LOONGSON2EF) += common/
+
+#
+# Lemote Fuloong mini-PC (Loongson 2E-based)
+#
+
+obj-$(CONFIG_LEMOTE_FULOONG2E)	+= fuloong-2e/
+
+#
+# Lemote loongson2f family machines
+#
+
+obj-$(CONFIG_LEMOTE_MACH2F)  += lemote-2f/
diff --git a/arch/mips/loongson2ef/Platform b/arch/mips/loongson2ef/Platform
new file mode 100644
index 0000000..ae023b9
--- /dev/null
+++ b/arch/mips/loongson2ef/Platform
@@ -0,0 +1,57 @@
+#
+# Loongson Processors' Support
+#
+
+# Only gcc >= 4.4 have Loongson specific support
+cflags-$(CONFIG_CPU_LOONGSON2EF)	+= -Wa,--trap
+cflags-$(CONFIG_CPU_LOONGSON2E) += \
+	$(call cc-option,-march=loongson2e,-march=r4600)
+cflags-$(CONFIG_CPU_LOONGSON2F) += \
+	$(call cc-option,-march=loongson2f,-march=r4600)
+#
+# Some versions of binutils, not currently mainline as of 2019/02/04, support
+# an -mfix-loongson3-llsc flag which emits a sync prior to each ll instruction
+# to work around a CPU bug (see __SYNC_loongson3_war in asm/sync.h for a
+# description).
+#
+# We disable this in order to prevent the assembler meddling with the
+# instruction that labels refer to, ie. if we label an ll instruction:
+#
+# 1: ll v0, 0(a0)
+#
+# ...then with the assembler fix applied the label may actually point at a sync
+# instruction inserted by the assembler, and if we were using the label in an
+# exception table the table would no longer contain the address of the ll
+# instruction.
+#
+# Avoid this by explicitly disabling that assembler behaviour. If upstream
+# binutils does not merge support for the flag then we can revisit & remove
+# this later - for now it ensures vendor toolchains don't cause problems.
+#
+cflags-$(CONFIG_CPU_LOONGSON2EF)	+= $(call as-option,-Wa$(comma)-mno-fix-loongson3-llsc,)
+
+# Enable the workarounds for Loongson2f
+ifdef CONFIG_CPU_LOONGSON2F_WORKAROUNDS
+  ifeq ($(call as-option,-Wa$(comma)-mfix-loongson2f-nop,),)
+    $(error only binutils >= 2.20.2 have needed option -mfix-loongson2f-nop)
+  else
+    cflags-$(CONFIG_CPU_NOP_WORKAROUNDS) += -Wa$(comma)-mfix-loongson2f-nop
+  endif
+  ifeq ($(call as-option,-Wa$(comma)-mfix-loongson2f-jump,),)
+    $(error only binutils >= 2.20.2 have needed option -mfix-loongson2f-jump)
+  else
+    cflags-$(CONFIG_CPU_JUMP_WORKAROUNDS) += -Wa$(comma)-mfix-loongson2f-jump
+  endif
+endif
+
+# Some -march= flags enable MMI instructions, and GCC complains about that
+# support being enabled alongside -msoft-float. Thus explicitly disable MMI.
+cflags-y += $(call cc-option,-mno-loongson-mmi)
+
+#
+# Loongson Machines' Support
+#
+
+cflags-$(CONFIG_MACH_LOONGSON2EF) += -I$(srctree)/arch/mips/include/asm/mach-loongson2ef -mno-branch-likely
+load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000
+load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000
diff --git a/arch/mips/loongson2ef/common/Makefile b/arch/mips/loongson2ef/common/Makefile
new file mode 100644
index 0000000..d5ab3e5
--- /dev/null
+++ b/arch/mips/loongson2ef/common/Makefile
@@ -0,0 +1,26 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for loongson based machines.
+#
+
+obj-y += setup.o init.o env.o time.o reset.o irq.o \
+    bonito-irq.o mem.o machtype.o platform.o serial.o
+obj-$(CONFIG_PCI) += pci.o
+
+#
+# Serial port support
+#
+obj-$(CONFIG_LOONGSON_UART_BASE) += uart_base.o
+obj-$(CONFIG_LOONGSON_MC146818) += rtc.o
+
+#
+# Enable CS5536 Virtual Support Module(VSM) to virtulize the PCI configure
+# space
+#
+obj-$(CONFIG_CS5536) += cs5536/
+
+#
+# Suspend Support
+#
+
+obj-$(CONFIG_SUSPEND) += pm.o
diff --git a/arch/mips/loongson2ef/common/bonito-irq.c b/arch/mips/loongson2ef/common/bonito-irq.c
new file mode 100644
index 0000000..c06ad41
--- /dev/null
+++ b/arch/mips/loongson2ef/common/bonito-irq.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ * Copyright (C) 2000, 2001 Ralf Baechle (ralf@gnu.org)
+ *
+ * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ */
+#include <linux/interrupt.h>
+#include <linux/compiler.h>
+
+#include <loongson.h>
+
+static inline void bonito_irq_enable(struct irq_data *d)
+{
+	LOONGSON_INTENSET = (1 << (d->irq - LOONGSON_IRQ_BASE));
+	mmiowb();
+}
+
+static inline void bonito_irq_disable(struct irq_data *d)
+{
+	LOONGSON_INTENCLR = (1 << (d->irq - LOONGSON_IRQ_BASE));
+	mmiowb();
+}
+
+static struct irq_chip bonito_irq_type = {
+	.name		= "bonito_irq",
+	.irq_mask	= bonito_irq_disable,
+	.irq_unmask	= bonito_irq_enable,
+};
+
+void bonito_irq_init(void)
+{
+	u32 i;
+
+	for (i = LOONGSON_IRQ_BASE; i < LOONGSON_IRQ_BASE + 32; i++)
+		irq_set_chip_and_handler(i, &bonito_irq_type,
+					 handle_level_irq);
+
+#ifdef CONFIG_CPU_LOONGSON2E
+	i = LOONGSON_IRQ_BASE + 10;
+	if (request_irq(i, no_action, 0, "dma_timeout", NULL))
+		pr_err("Failed to request irq %d (dma_timeout)\n", i);
+#endif
+}
diff --git a/arch/mips/loongson2ef/common/cs5536/Makefile b/arch/mips/loongson2ef/common/cs5536/Makefile
new file mode 100644
index 0000000..b32b296
--- /dev/null
+++ b/arch/mips/loongson2ef/common/cs5536/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for CS5536 support.
+#
+
+obj-$(CONFIG_CS5536) += cs5536_pci.o cs5536_ide.o cs5536_acc.o cs5536_ohci.o \
+			cs5536_isa.o cs5536_ehci.o
+
+#
+# Enable cs5536 mfgpt Timer
+#
+obj-$(CONFIG_CS5536_MFGPT) += cs5536_mfgpt.o
diff --git a/arch/mips/loongson2ef/common/cs5536/cs5536_acc.c b/arch/mips/loongson2ef/common/cs5536/cs5536_acc.c
new file mode 100644
index 0000000..ff50aae
--- /dev/null
+++ b/arch/mips/loongson2ef/common/cs5536/cs5536_acc.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * the ACC Virtual Support Module of AMD CS5536
+ *
+ * Copyright (C) 2007 Lemote, Inc.
+ * Author : jlliu, liujl@lemote.com
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ */
+
+#include <cs5536/cs5536.h>
+#include <cs5536/cs5536_pci.h>
+
+void pci_acc_write_reg(int reg, u32 value)
+{
+	u32 hi = 0, lo = value;
+
+	switch (reg) {
+	case PCI_COMMAND:
+		_rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
+		if (value & PCI_COMMAND_MASTER)
+			lo |= (0x03 << 8);
+		else
+			lo &= ~(0x03 << 8);
+		_wrmsr(GLIU_MSR_REG(GLIU_PAE), hi, lo);
+		break;
+	case PCI_STATUS:
+		if (value & PCI_STATUS_PARITY) {
+			_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+			if (lo & SB_PARE_ERR_FLAG) {
+				lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG;
+				_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
+			}
+		}
+		break;
+	case PCI_BAR0_REG:
+		if (value == PCI_BAR_RANGE_MASK) {
+			_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+			lo |= SOFT_BAR_ACC_FLAG;
+			_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+		} else if (value & 0x01) {
+			value &= 0xfffffffc;
+			hi = 0xA0000000 | ((value & 0x000ff000) >> 12);
+			lo = 0x000fff80 | ((value & 0x00000fff) << 20);
+			_wrmsr(GLIU_MSR_REG(GLIU_IOD_BM1), hi, lo);
+		}
+		break;
+	case PCI_ACC_INT_REG:
+		_rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo);
+		/* disable all the usb interrupt in PIC */
+		lo &= ~(0xf << PIC_YSEL_LOW_ACC_SHIFT);
+		if (value)	/* enable all the acc interrupt in PIC */
+			lo |= (CS5536_ACC_INTR << PIC_YSEL_LOW_ACC_SHIFT);
+		_wrmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), hi, lo);
+		break;
+	default:
+		break;
+	}
+}
+
+u32 pci_acc_read_reg(int reg)
+{
+	u32 hi, lo;
+	u32 conf_data = 0;
+
+	switch (reg) {
+	case PCI_VENDOR_ID:
+		conf_data =
+		    CFG_PCI_VENDOR_ID(CS5536_ACC_DEVICE_ID, CS5536_VENDOR_ID);
+		break;
+	case PCI_COMMAND:
+		_rdmsr(GLIU_MSR_REG(GLIU_IOD_BM1), &hi, &lo);
+		if (((lo & 0xfff00000) || (hi & 0x000000ff))
+		    && ((hi & 0xf0000000) == 0xa0000000))
+			conf_data |= PCI_COMMAND_IO;
+		_rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
+		if ((lo & 0x300) == 0x300)
+			conf_data |= PCI_COMMAND_MASTER;
+		break;
+	case PCI_STATUS:
+		conf_data |= PCI_STATUS_66MHZ;
+		conf_data |= PCI_STATUS_FAST_BACK;
+		_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+		if (lo & SB_PARE_ERR_FLAG)
+			conf_data |= PCI_STATUS_PARITY;
+		conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+		break;
+	case PCI_CLASS_REVISION:
+		_rdmsr(ACC_MSR_REG(ACC_CAP), &hi, &lo);
+		conf_data = lo & 0x000000ff;
+		conf_data |= (CS5536_ACC_CLASS_CODE << 8);
+		break;
+	case PCI_CACHE_LINE_SIZE:
+		conf_data =
+		    CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
+					    PCI_NORMAL_LATENCY_TIMER);
+		break;
+	case PCI_BAR0_REG:
+		_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+		if (lo & SOFT_BAR_ACC_FLAG) {
+			conf_data = CS5536_ACC_RANGE |
+			    PCI_BASE_ADDRESS_SPACE_IO;
+			lo &= ~SOFT_BAR_ACC_FLAG;
+			_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+		} else {
+			_rdmsr(GLIU_MSR_REG(GLIU_IOD_BM1), &hi, &lo);
+			conf_data = (hi & 0x000000ff) << 12;
+			conf_data |= (lo & 0xfff00000) >> 20;
+			conf_data |= 0x01;
+			conf_data &= ~0x02;
+		}
+		break;
+	case PCI_CARDBUS_CIS:
+		conf_data = PCI_CARDBUS_CIS_POINTER;
+		break;
+	case PCI_SUBSYSTEM_VENDOR_ID:
+		conf_data =
+		    CFG_PCI_VENDOR_ID(CS5536_ACC_SUB_ID, CS5536_SUB_VENDOR_ID);
+		break;
+	case PCI_ROM_ADDRESS:
+		conf_data = PCI_EXPANSION_ROM_BAR;
+		break;
+	case PCI_CAPABILITY_LIST:
+		conf_data = PCI_CAPLIST_USB_POINTER;
+		break;
+	case PCI_INTERRUPT_LINE:
+		conf_data =
+		    CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_ACC_INTR);
+		break;
+	default:
+		break;
+	}
+
+	return conf_data;
+}
diff --git a/arch/mips/loongson2ef/common/cs5536/cs5536_ehci.c b/arch/mips/loongson2ef/common/cs5536/cs5536_ehci.c
new file mode 100644
index 0000000..bd4c39f
--- /dev/null
+++ b/arch/mips/loongson2ef/common/cs5536/cs5536_ehci.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * the EHCI Virtual Support Module of AMD CS5536
+ *
+ * Copyright (C) 2007 Lemote, Inc.
+ * Author : jlliu, liujl@lemote.com
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ */
+
+#include <cs5536/cs5536.h>
+#include <cs5536/cs5536_pci.h>
+
+void pci_ehci_write_reg(int reg, u32 value)
+{
+	u32 hi = 0, lo = value;
+
+	switch (reg) {
+	case PCI_COMMAND:
+		_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+		if (value & PCI_COMMAND_MASTER)
+			hi |= PCI_COMMAND_MASTER;
+		else
+			hi &= ~PCI_COMMAND_MASTER;
+
+		if (value & PCI_COMMAND_MEMORY)
+			hi |= PCI_COMMAND_MEMORY;
+		else
+			hi &= ~PCI_COMMAND_MEMORY;
+		_wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
+		break;
+	case PCI_STATUS:
+		if (value & PCI_STATUS_PARITY) {
+			_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+			if (lo & SB_PARE_ERR_FLAG) {
+				lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG;
+				_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
+			}
+		}
+		break;
+	case PCI_BAR0_REG:
+		if (value == PCI_BAR_RANGE_MASK) {
+			_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+			lo |= SOFT_BAR_EHCI_FLAG;
+			_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+		} else if ((value & 0x01) == 0x00) {
+			_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+			lo = value;
+			_wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
+
+			value &= 0xfffffff0;
+			hi = 0x40000000 | ((value & 0xff000000) >> 24);
+			lo = 0x000fffff | ((value & 0x00fff000) << 8);
+			_wrmsr(GLIU_MSR_REG(GLIU_P2D_BM4), hi, lo);
+		}
+		break;
+	case PCI_EHCI_LEGSMIEN_REG:
+		_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+		hi &= 0x003f0000;
+		hi |= (value & 0x3f) << 16;
+		_wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
+		break;
+	case PCI_EHCI_FLADJ_REG:
+		_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+		hi &= ~0x00003f00;
+		hi |= value & 0x00003f00;
+		_wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
+		break;
+	default:
+		break;
+	}
+}
+
+u32 pci_ehci_read_reg(int reg)
+{
+	u32 conf_data = 0;
+	u32 hi, lo;
+
+	switch (reg) {
+	case PCI_VENDOR_ID:
+		conf_data =
+		    CFG_PCI_VENDOR_ID(CS5536_EHCI_DEVICE_ID, CS5536_VENDOR_ID);
+		break;
+	case PCI_COMMAND:
+		_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+		if (hi & PCI_COMMAND_MASTER)
+			conf_data |= PCI_COMMAND_MASTER;
+		if (hi & PCI_COMMAND_MEMORY)
+			conf_data |= PCI_COMMAND_MEMORY;
+		break;
+	case PCI_STATUS:
+		conf_data |= PCI_STATUS_66MHZ;
+		conf_data |= PCI_STATUS_FAST_BACK;
+		_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+		if (lo & SB_PARE_ERR_FLAG)
+			conf_data |= PCI_STATUS_PARITY;
+		conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+		break;
+	case PCI_CLASS_REVISION:
+		_rdmsr(USB_MSR_REG(USB_CAP), &hi, &lo);
+		conf_data = lo & 0x000000ff;
+		conf_data |= (CS5536_EHCI_CLASS_CODE << 8);
+		break;
+	case PCI_CACHE_LINE_SIZE:
+		conf_data =
+		    CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
+					    PCI_NORMAL_LATENCY_TIMER);
+		break;
+	case PCI_BAR0_REG:
+		_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+		if (lo & SOFT_BAR_EHCI_FLAG) {
+			conf_data = CS5536_EHCI_RANGE |
+			    PCI_BASE_ADDRESS_SPACE_MEMORY;
+			lo &= ~SOFT_BAR_EHCI_FLAG;
+			_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+		} else {
+			_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+			conf_data = lo & 0xfffff000;
+		}
+		break;
+	case PCI_CARDBUS_CIS:
+		conf_data = PCI_CARDBUS_CIS_POINTER;
+		break;
+	case PCI_SUBSYSTEM_VENDOR_ID:
+		conf_data =
+		    CFG_PCI_VENDOR_ID(CS5536_EHCI_SUB_ID, CS5536_SUB_VENDOR_ID);
+		break;
+	case PCI_ROM_ADDRESS:
+		conf_data = PCI_EXPANSION_ROM_BAR;
+		break;
+	case PCI_CAPABILITY_LIST:
+		conf_data = PCI_CAPLIST_USB_POINTER;
+		break;
+	case PCI_INTERRUPT_LINE:
+		conf_data =
+		    CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
+		break;
+	case PCI_EHCI_LEGSMIEN_REG:
+		_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+		conf_data = (hi & 0x003f0000) >> 16;
+		break;
+	case PCI_EHCI_LEGSMISTS_REG:
+		_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+		conf_data = (hi & 0x3f000000) >> 24;
+		break;
+	case PCI_EHCI_FLADJ_REG:
+		_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+		conf_data = hi & 0x00003f00;
+		break;
+	default:
+		break;
+	}
+
+	return conf_data;
+}
diff --git a/arch/mips/loongson2ef/common/cs5536/cs5536_ide.c b/arch/mips/loongson2ef/common/cs5536/cs5536_ide.c
new file mode 100644
index 0000000..bb93329
--- /dev/null
+++ b/arch/mips/loongson2ef/common/cs5536/cs5536_ide.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * the IDE Virtual Support Module of AMD CS5536
+ *
+ * Copyright (C) 2007 Lemote, Inc.
+ * Author : jlliu, liujl@lemote.com
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ */
+
+#include <cs5536/cs5536.h>
+#include <cs5536/cs5536_pci.h>
+
+void pci_ide_write_reg(int reg, u32 value)
+{
+	u32 hi = 0, lo = value;
+
+	switch (reg) {
+	case PCI_COMMAND:
+		_rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
+		if (value & PCI_COMMAND_MASTER)
+			lo |= (0x03 << 4);
+		else
+			lo &= ~(0x03 << 4);
+		_wrmsr(GLIU_MSR_REG(GLIU_PAE), hi, lo);
+		break;
+	case PCI_STATUS:
+		if (value & PCI_STATUS_PARITY) {
+			_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+			if (lo & SB_PARE_ERR_FLAG) {
+				lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG;
+				_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
+			}
+		}
+		break;
+	case PCI_CACHE_LINE_SIZE:
+		value &= 0x0000ff00;
+		_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
+		hi &= 0xffffff00;
+		hi |= (value >> 8);
+		_wrmsr(SB_MSR_REG(SB_CTRL), hi, lo);
+		break;
+	case PCI_BAR4_REG:
+		if (value == PCI_BAR_RANGE_MASK) {
+			_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+			lo |= SOFT_BAR_IDE_FLAG;
+			_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+		} else if (value & 0x01) {
+			_rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
+			lo = (value & 0xfffffff0) | 0x1;
+			_wrmsr(IDE_MSR_REG(IDE_IO_BAR), hi, lo);
+
+			value &= 0xfffffffc;
+			hi = 0x60000000 | ((value & 0x000ff000) >> 12);
+			lo = 0x000ffff0 | ((value & 0x00000fff) << 20);
+			_wrmsr(GLIU_MSR_REG(GLIU_IOD_BM2), hi, lo);
+		}
+		break;
+	case PCI_IDE_CFG_REG:
+		if (value == CS5536_IDE_FLASH_SIGNATURE) {
+			_rdmsr(DIVIL_MSR_REG(DIVIL_BALL_OPTS), &hi, &lo);
+			lo |= 0x01;
+			_wrmsr(DIVIL_MSR_REG(DIVIL_BALL_OPTS), hi, lo);
+		} else {
+			_rdmsr(IDE_MSR_REG(IDE_CFG), &hi, &lo);
+			lo = value;
+			_wrmsr(IDE_MSR_REG(IDE_CFG), hi, lo);
+		}
+		break;
+	case PCI_IDE_DTC_REG:
+		_rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo);
+		lo = value;
+		_wrmsr(IDE_MSR_REG(IDE_DTC), hi, lo);
+		break;
+	case PCI_IDE_CAST_REG:
+		_rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo);
+		lo = value;
+		_wrmsr(IDE_MSR_REG(IDE_CAST), hi, lo);
+		break;
+	case PCI_IDE_ETC_REG:
+		_rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
+		lo = value;
+		_wrmsr(IDE_MSR_REG(IDE_ETC), hi, lo);
+		break;
+	case PCI_IDE_PM_REG:
+		_rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
+		lo = value;
+		_wrmsr(IDE_MSR_REG(IDE_INTERNAL_PM), hi, lo);
+		break;
+	default:
+		break;
+	}
+}
+
+u32 pci_ide_read_reg(int reg)
+{
+	u32 conf_data = 0;
+	u32 hi, lo;
+
+	switch (reg) {
+	case PCI_VENDOR_ID:
+		conf_data =
+		    CFG_PCI_VENDOR_ID(CS5536_IDE_DEVICE_ID, CS5536_VENDOR_ID);
+		break;
+	case PCI_COMMAND:
+		_rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
+		if (lo & 0xfffffff0)
+			conf_data |= PCI_COMMAND_IO;
+		_rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
+		if ((lo & 0x30) == 0x30)
+			conf_data |= PCI_COMMAND_MASTER;
+		break;
+	case PCI_STATUS:
+		conf_data |= PCI_STATUS_66MHZ;
+		conf_data |= PCI_STATUS_FAST_BACK;
+		_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+		if (lo & SB_PARE_ERR_FLAG)
+			conf_data |= PCI_STATUS_PARITY;
+		conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+		break;
+	case PCI_CLASS_REVISION:
+		_rdmsr(IDE_MSR_REG(IDE_CAP), &hi, &lo);
+		conf_data = lo & 0x000000ff;
+		conf_data |= (CS5536_IDE_CLASS_CODE << 8);
+		break;
+	case PCI_CACHE_LINE_SIZE:
+		_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
+		hi &= 0x000000f8;
+		conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE, hi);
+		break;
+	case PCI_BAR4_REG:
+		_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+		if (lo & SOFT_BAR_IDE_FLAG) {
+			conf_data = CS5536_IDE_RANGE |
+			    PCI_BASE_ADDRESS_SPACE_IO;
+			lo &= ~SOFT_BAR_IDE_FLAG;
+			_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+		} else {
+			_rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
+			conf_data = lo & 0xfffffff0;
+			conf_data |= 0x01;
+			conf_data &= ~0x02;
+		}
+		break;
+	case PCI_CARDBUS_CIS:
+		conf_data = PCI_CARDBUS_CIS_POINTER;
+		break;
+	case PCI_SUBSYSTEM_VENDOR_ID:
+		conf_data =
+		    CFG_PCI_VENDOR_ID(CS5536_IDE_SUB_ID, CS5536_SUB_VENDOR_ID);
+		break;
+	case PCI_ROM_ADDRESS:
+		conf_data = PCI_EXPANSION_ROM_BAR;
+		break;
+	case PCI_CAPABILITY_LIST:
+		conf_data = PCI_CAPLIST_POINTER;
+		break;
+	case PCI_INTERRUPT_LINE:
+		conf_data =
+		    CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_IDE_INTR);
+		break;
+	case PCI_IDE_CFG_REG:
+		_rdmsr(IDE_MSR_REG(IDE_CFG), &hi, &lo);
+		conf_data = lo;
+		break;
+	case PCI_IDE_DTC_REG:
+		_rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo);
+		conf_data = lo;
+		break;
+	case PCI_IDE_CAST_REG:
+		_rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo);
+		conf_data = lo;
+		break;
+	case PCI_IDE_ETC_REG:
+		_rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
+		conf_data = lo;
+		break;
+	case PCI_IDE_PM_REG:
+		_rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
+		conf_data = lo;
+		break;
+	default:
+		break;
+	}
+
+	return conf_data;
+}
diff --git a/arch/mips/loongson2ef/common/cs5536/cs5536_isa.c b/arch/mips/loongson2ef/common/cs5536/cs5536_isa.c
new file mode 100644
index 0000000..5ad38f8
--- /dev/null
+++ b/arch/mips/loongson2ef/common/cs5536/cs5536_isa.c
@@ -0,0 +1,326 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * the ISA Virtual Support Module of AMD CS5536
+ *
+ * Copyright (C) 2007 Lemote, Inc.
+ * Author : jlliu, liujl@lemote.com
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ */
+
+#include <linux/pci.h>
+#include <cs5536/cs5536.h>
+#include <cs5536/cs5536_pci.h>
+
+/* common variables for PCI_ISA_READ/WRITE_BAR */
+static const u32 divil_msr_reg[6] = {
+	DIVIL_MSR_REG(DIVIL_LBAR_SMB), DIVIL_MSR_REG(DIVIL_LBAR_GPIO),
+	DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), DIVIL_MSR_REG(DIVIL_LBAR_IRQ),
+	DIVIL_MSR_REG(DIVIL_LBAR_PMS), DIVIL_MSR_REG(DIVIL_LBAR_ACPI),
+};
+
+static const u32 soft_bar_flag[6] = {
+	SOFT_BAR_SMB_FLAG, SOFT_BAR_GPIO_FLAG, SOFT_BAR_MFGPT_FLAG,
+	SOFT_BAR_IRQ_FLAG, SOFT_BAR_PMS_FLAG, SOFT_BAR_ACPI_FLAG,
+};
+
+static const u32 sb_msr_reg[6] = {
+	SB_MSR_REG(SB_R0), SB_MSR_REG(SB_R1), SB_MSR_REG(SB_R2),
+	SB_MSR_REG(SB_R3), SB_MSR_REG(SB_R4), SB_MSR_REG(SB_R5),
+};
+
+static const u32 bar_space_range[6] = {
+	CS5536_SMB_RANGE, CS5536_GPIO_RANGE, CS5536_MFGPT_RANGE,
+	CS5536_IRQ_RANGE, CS5536_PMS_RANGE, CS5536_ACPI_RANGE,
+};
+
+static const int bar_space_len[6] = {
+	CS5536_SMB_LENGTH, CS5536_GPIO_LENGTH, CS5536_MFGPT_LENGTH,
+	CS5536_IRQ_LENGTH, CS5536_PMS_LENGTH, CS5536_ACPI_LENGTH,
+};
+
+/*
+ * enable the divil module bar space.
+ *
+ * For all the DIVIL module LBAR, you should control the DIVIL LBAR reg
+ * and the RCONFx(0~5) reg to use the modules.
+ */
+static void divil_lbar_enable(void)
+{
+	u32 hi, lo;
+	int offset;
+
+	/*
+	 * The DIVIL IRQ is not used yet. and make the RCONF0 reserved.
+	 */
+
+	for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
+		_rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
+		hi |= 0x01;
+		_wrmsr(DIVIL_MSR_REG(offset), hi, lo);
+	}
+}
+
+/*
+ * disable the divil module bar space.
+ */
+static void divil_lbar_disable(void)
+{
+	u32 hi, lo;
+	int offset;
+
+	for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
+		_rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
+		hi &= ~0x01;
+		_wrmsr(DIVIL_MSR_REG(offset), hi, lo);
+	}
+}
+
+/*
+ * BAR write: write value to the n BAR
+ */
+
+void pci_isa_write_bar(int n, u32 value)
+{
+	u32 hi = 0, lo = value;
+
+	if (value == PCI_BAR_RANGE_MASK) {
+		_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+		lo |= soft_bar_flag[n];
+		_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+	} else if (value & 0x01) {
+		/* NATIVE reg */
+		hi = 0x0000f001;
+		lo &= bar_space_range[n];
+		_wrmsr(divil_msr_reg[n], hi, lo);
+
+		/* RCONFx is 4bytes in units for I/O space */
+		hi = ((value & 0x000ffffc) << 12) |
+		    ((bar_space_len[n] - 4) << 12) | 0x01;
+		lo = ((value & 0x000ffffc) << 12) | 0x01;
+		_wrmsr(sb_msr_reg[n], hi, lo);
+	}
+}
+
+/*
+ * BAR read: read the n BAR
+ */
+
+u32 pci_isa_read_bar(int n)
+{
+	u32 conf_data = 0;
+	u32 hi, lo;
+
+	_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+	if (lo & soft_bar_flag[n]) {
+		conf_data = bar_space_range[n] | PCI_BASE_ADDRESS_SPACE_IO;
+		lo &= ~soft_bar_flag[n];
+		_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+	} else {
+		_rdmsr(divil_msr_reg[n], &hi, &lo);
+		conf_data = lo & bar_space_range[n];
+		conf_data |= 0x01;
+		conf_data &= ~0x02;
+	}
+	return conf_data;
+}
+
+/*
+ * isa_write: ISA write transfer
+ *
+ * We assume that this is not a bus master transfer.
+ */
+void pci_isa_write_reg(int reg, u32 value)
+{
+	u32 hi = 0, lo = value;
+	u32 temp;
+
+	switch (reg) {
+	case PCI_COMMAND:
+		if (value & PCI_COMMAND_IO)
+			divil_lbar_enable();
+		else
+			divil_lbar_disable();
+		break;
+	case PCI_STATUS:
+		_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+		temp = lo & 0x0000ffff;
+		if ((value & PCI_STATUS_SIG_TARGET_ABORT) &&
+		    (lo & SB_TAS_ERR_EN))
+			temp |= SB_TAS_ERR_FLAG;
+
+		if ((value & PCI_STATUS_REC_TARGET_ABORT) &&
+		    (lo & SB_TAR_ERR_EN))
+			temp |= SB_TAR_ERR_FLAG;
+
+		if ((value & PCI_STATUS_REC_MASTER_ABORT)
+		    && (lo & SB_MAR_ERR_EN))
+			temp |= SB_MAR_ERR_FLAG;
+
+		if ((value & PCI_STATUS_DETECTED_PARITY)
+		    && (lo & SB_PARE_ERR_EN))
+			temp |= SB_PARE_ERR_FLAG;
+
+		lo = temp;
+		_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
+		break;
+	case PCI_CACHE_LINE_SIZE:
+		value &= 0x0000ff00;
+		_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
+		hi &= 0xffffff00;
+		hi |= (value >> 8);
+		_wrmsr(SB_MSR_REG(SB_CTRL), hi, lo);
+		break;
+	case PCI_BAR0_REG:
+		pci_isa_write_bar(0, value);
+		break;
+	case PCI_BAR1_REG:
+		pci_isa_write_bar(1, value);
+		break;
+	case PCI_BAR2_REG:
+		pci_isa_write_bar(2, value);
+		break;
+	case PCI_BAR3_REG:
+		pci_isa_write_bar(3, value);
+		break;
+	case PCI_BAR4_REG:
+		pci_isa_write_bar(4, value);
+		break;
+	case PCI_BAR5_REG:
+		pci_isa_write_bar(5, value);
+		break;
+	case PCI_UART1_INT_REG:
+		_rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);
+		/* disable uart1 interrupt in PIC */
+		lo &= ~(0xf << 24);
+		if (value)	/* enable uart1 interrupt in PIC */
+			lo |= (CS5536_UART1_INTR << 24);
+		_wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo);
+		break;
+	case PCI_UART2_INT_REG:
+		_rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);
+		/* disable uart2 interrupt in PIC */
+		lo &= ~(0xf << 28);
+		if (value)	/* enable uart2 interrupt in PIC */
+			lo |= (CS5536_UART2_INTR << 28);
+		_wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo);
+		break;
+	case PCI_ISA_FIXUP_REG:
+		if (value) {
+			/* enable the TARGET ABORT/MASTER ABORT etc. */
+			_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+			lo |= 0x00000063;
+			_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
+		}
+
+	default:
+		/* ALL OTHER PCI CONFIG SPACE HEADER IS NOT IMPLEMENTED. */
+		break;
+	}
+}
+
+/*
+ * isa_read: ISA read transfers
+ *
+ * We assume that this is not a bus master transfer.
+ */
+u32 pci_isa_read_reg(int reg)
+{
+	u32 conf_data = 0;
+	u32 hi, lo;
+
+	switch (reg) {
+	case PCI_VENDOR_ID:
+		conf_data =
+		    CFG_PCI_VENDOR_ID(CS5536_ISA_DEVICE_ID, CS5536_VENDOR_ID);
+		break;
+	case PCI_COMMAND:
+		/* we just check the first LBAR for the IO enable bit, */
+		/* maybe we should changed later. */
+		_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), &hi, &lo);
+		if (hi & 0x01)
+			conf_data |= PCI_COMMAND_IO;
+		break;
+	case PCI_STATUS:
+		conf_data |= PCI_STATUS_66MHZ;
+		conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+		conf_data |= PCI_STATUS_FAST_BACK;
+
+		_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+		if (lo & SB_TAS_ERR_FLAG)
+			conf_data |= PCI_STATUS_SIG_TARGET_ABORT;
+		if (lo & SB_TAR_ERR_FLAG)
+			conf_data |= PCI_STATUS_REC_TARGET_ABORT;
+		if (lo & SB_MAR_ERR_FLAG)
+			conf_data |= PCI_STATUS_REC_MASTER_ABORT;
+		if (lo & SB_PARE_ERR_FLAG)
+			conf_data |= PCI_STATUS_DETECTED_PARITY;
+		break;
+	case PCI_CLASS_REVISION:
+		_rdmsr(GLCP_MSR_REG(GLCP_CHIP_REV_ID), &hi, &lo);
+		conf_data = lo & 0x000000ff;
+		conf_data |= (CS5536_ISA_CLASS_CODE << 8);
+		break;
+	case PCI_CACHE_LINE_SIZE:
+		_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
+		hi &= 0x000000f8;
+		conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_BRIDGE_HEADER_TYPE, hi);
+		break;
+		/*
+		 * we only use the LBAR of DIVIL, no RCONF used.
+		 * all of them are IO space.
+		 */
+	case PCI_BAR0_REG:
+		return pci_isa_read_bar(0);
+		break;
+	case PCI_BAR1_REG:
+		return pci_isa_read_bar(1);
+		break;
+	case PCI_BAR2_REG:
+		return pci_isa_read_bar(2);
+		break;
+	case PCI_BAR3_REG:
+		break;
+	case PCI_BAR4_REG:
+		return pci_isa_read_bar(4);
+		break;
+	case PCI_BAR5_REG:
+		return pci_isa_read_bar(5);
+		break;
+	case PCI_CARDBUS_CIS:
+		conf_data = PCI_CARDBUS_CIS_POINTER;
+		break;
+	case PCI_SUBSYSTEM_VENDOR_ID:
+		conf_data =
+		    CFG_PCI_VENDOR_ID(CS5536_ISA_SUB_ID, CS5536_SUB_VENDOR_ID);
+		break;
+	case PCI_ROM_ADDRESS:
+		conf_data = PCI_EXPANSION_ROM_BAR;
+		break;
+	case PCI_CAPABILITY_LIST:
+		conf_data = PCI_CAPLIST_POINTER;
+		break;
+	case PCI_INTERRUPT_LINE:
+		/* no interrupt used here */
+		conf_data = CFG_PCI_INTERRUPT_LINE(0x00, 0x00);
+		break;
+	default:
+		break;
+	}
+
+	return conf_data;
+}
+
+/*
+ * The mfgpt timer interrupt is running early, so we must keep the south bridge
+ * mmio always enabled. Otherwise we may race with the PCI configuration which
+ * may temporarily disable it. When that happens and the timer interrupt fires,
+ * we are not able to clear it and the system will hang.
+ */
+static void cs5536_isa_mmio_always_on(struct pci_dev *dev)
+{
+	dev->mmio_always_on = 1;
+}
+DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA,
+	PCI_CLASS_BRIDGE_ISA, 8, cs5536_isa_mmio_always_on);
diff --git a/arch/mips/loongson2ef/common/cs5536/cs5536_mfgpt.c b/arch/mips/loongson2ef/common/cs5536/cs5536_mfgpt.c
new file mode 100644
index 0000000..f21a540
--- /dev/null
+++ b/arch/mips/loongson2ef/common/cs5536/cs5536_mfgpt.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * CS5536 General timer functions
+ *
+ * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
+ * Author: Yanhua, yanh@lemote.com
+ *
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu zhangjin, wuzhangjin@gmail.com
+ *
+ * Reference: AMD Geode(TM) CS5536 Companion Device Data Book
+ */
+
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/export.h>
+#include <linux/jiffies.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+
+#include <asm/time.h>
+
+#include <cs5536/cs5536_mfgpt.h>
+
+static DEFINE_RAW_SPINLOCK(mfgpt_lock);
+
+static u32 mfgpt_base;
+
+/*
+ * Initialize the MFGPT timer.
+ *
+ * This is also called after resume to bring the MFGPT into operation again.
+ */
+
+/* disable counter */
+void disable_mfgpt0_counter(void)
+{
+	outw(inw(MFGPT0_SETUP) & 0x7fff, MFGPT0_SETUP);
+}
+EXPORT_SYMBOL(disable_mfgpt0_counter);
+
+/* enable counter, comparator2 to event mode, 14.318MHz clock */
+void enable_mfgpt0_counter(void)
+{
+	outw(0xe310, MFGPT0_SETUP);
+}
+EXPORT_SYMBOL(enable_mfgpt0_counter);
+
+static int mfgpt_timer_set_periodic(struct clock_event_device *evt)
+{
+	raw_spin_lock(&mfgpt_lock);
+
+	outw(COMPARE, MFGPT0_CMP2);	/* set comparator2 */
+	outw(0, MFGPT0_CNT);		/* set counter to 0 */
+	enable_mfgpt0_counter();
+
+	raw_spin_unlock(&mfgpt_lock);
+	return 0;
+}
+
+static int mfgpt_timer_shutdown(struct clock_event_device *evt)
+{
+	if (clockevent_state_periodic(evt) || clockevent_state_oneshot(evt)) {
+		raw_spin_lock(&mfgpt_lock);
+		disable_mfgpt0_counter();
+		raw_spin_unlock(&mfgpt_lock);
+	}
+
+	return 0;
+}
+
+static struct clock_event_device mfgpt_clockevent = {
+	.name = "mfgpt",
+	.features = CLOCK_EVT_FEAT_PERIODIC,
+
+	/* The oneshot mode have very high deviation, don't use it! */
+	.set_state_shutdown = mfgpt_timer_shutdown,
+	.set_state_periodic = mfgpt_timer_set_periodic,
+	.irq = CS5536_MFGPT_INTR,
+};
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+	u32 basehi;
+
+	/*
+	 * get MFGPT base address
+	 *
+	 * NOTE: do not remove me, it's need for the value of mfgpt_base is
+	 * variable
+	 */
+	_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
+
+	/* ack */
+	outw(inw(MFGPT0_SETUP) | 0x4000, MFGPT0_SETUP);
+
+	mfgpt_clockevent.event_handler(&mfgpt_clockevent);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Initialize the conversion factor and the min/max deltas of the clock event
+ * structure and register the clock event source with the framework.
+ */
+void __init setup_mfgpt0_timer(void)
+{
+	u32 basehi;
+	struct clock_event_device *cd = &mfgpt_clockevent;
+	unsigned int cpu = smp_processor_id();
+
+	cd->cpumask = cpumask_of(cpu);
+	clockevent_set_clock(cd, MFGPT_TICK_RATE);
+	cd->max_delta_ns = clockevent_delta2ns(0xffff, cd);
+	cd->max_delta_ticks = 0xffff;
+	cd->min_delta_ns = clockevent_delta2ns(0xf, cd);
+	cd->min_delta_ticks = 0xf;
+
+	/* Enable MFGPT0 Comparator 2 Output to the Interrupt Mapper */
+	_wrmsr(DIVIL_MSR_REG(MFGPT_IRQ), 0, 0x100);
+
+	/* Enable Interrupt Gate 5 */
+	_wrmsr(DIVIL_MSR_REG(PIC_ZSEL_LOW), 0, 0x50000);
+
+	/* get MFGPT base address */
+	_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
+
+	clockevents_register_device(cd);
+
+	if (request_irq(CS5536_MFGPT_INTR, timer_interrupt,
+			IRQF_NOBALANCING | IRQF_TIMER, "timer", NULL))
+		pr_err("Failed to register timer interrupt\n");
+}
+
+/*
+ * Since the MFGPT overflows every tick, its not very useful
+ * to just read by itself. So use jiffies to emulate a free
+ * running counter:
+ */
+static u64 mfgpt_read(struct clocksource *cs)
+{
+	unsigned long flags;
+	int count;
+	u32 jifs;
+	static int old_count;
+	static u32 old_jifs;
+
+	raw_spin_lock_irqsave(&mfgpt_lock, flags);
+	/*
+	 * Although our caller may have the read side of xtime_lock,
+	 * this is now a seqlock, and we are cheating in this routine
+	 * by having side effects on state that we cannot undo if
+	 * there is a collision on the seqlock and our caller has to
+	 * retry.  (Namely, old_jifs and old_count.)  So we must treat
+	 * jiffies as volatile despite the lock.  We read jiffies
+	 * before latching the timer count to guarantee that although
+	 * the jiffies value might be older than the count (that is,
+	 * the counter may underflow between the last point where
+	 * jiffies was incremented and the point where we latch the
+	 * count), it cannot be newer.
+	 */
+	jifs = jiffies;
+	/* read the count */
+	count = inw(MFGPT0_CNT);
+
+	/*
+	 * It's possible for count to appear to go the wrong way for this
+	 * reason:
+	 *
+	 *  The timer counter underflows, but we haven't handled the resulting
+	 *  interrupt and incremented jiffies yet.
+	 *
+	 * Previous attempts to handle these cases intelligently were buggy, so
+	 * we just do the simple thing now.
+	 */
+	if (count < old_count && jifs == old_jifs)
+		count = old_count;
+
+	old_count = count;
+	old_jifs = jifs;
+
+	raw_spin_unlock_irqrestore(&mfgpt_lock, flags);
+
+	return (u64) (jifs * COMPARE) + count;
+}
+
+static struct clocksource clocksource_mfgpt = {
+	.name = "mfgpt",
+	.rating = 120, /* Functional for real use, but not desired */
+	.read = mfgpt_read,
+	.mask = CLOCKSOURCE_MASK(32),
+};
+
+int __init init_mfgpt_clocksource(void)
+{
+	if (num_possible_cpus() > 1)	/* MFGPT does not scale! */
+		return 0;
+
+	return clocksource_register_hz(&clocksource_mfgpt, MFGPT_TICK_RATE);
+}
+
+arch_initcall(init_mfgpt_clocksource);
diff --git a/arch/mips/loongson2ef/common/cs5536/cs5536_ohci.c b/arch/mips/loongson2ef/common/cs5536/cs5536_ohci.c
new file mode 100644
index 0000000..71a52b1
--- /dev/null
+++ b/arch/mips/loongson2ef/common/cs5536/cs5536_ohci.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * the OHCI Virtual Support Module of AMD CS5536
+ *
+ * Copyright (C) 2007 Lemote, Inc.
+ * Author : jlliu, liujl@lemote.com
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ */
+
+#include <cs5536/cs5536.h>
+#include <cs5536/cs5536_pci.h>
+
+void pci_ohci_write_reg(int reg, u32 value)
+{
+	u32 hi = 0, lo = value;
+
+	switch (reg) {
+	case PCI_COMMAND:
+		_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
+		if (value & PCI_COMMAND_MASTER)
+			hi |= PCI_COMMAND_MASTER;
+		else
+			hi &= ~PCI_COMMAND_MASTER;
+
+		if (value & PCI_COMMAND_MEMORY)
+			hi |= PCI_COMMAND_MEMORY;
+		else
+			hi &= ~PCI_COMMAND_MEMORY;
+		_wrmsr(USB_MSR_REG(USB_OHCI), hi, lo);
+		break;
+	case PCI_STATUS:
+		if (value & PCI_STATUS_PARITY) {
+			_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+			if (lo & SB_PARE_ERR_FLAG) {
+				lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG;
+				_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
+			}
+		}
+		break;
+	case PCI_BAR0_REG:
+		if (value == PCI_BAR_RANGE_MASK) {
+			_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+			lo |= SOFT_BAR_OHCI_FLAG;
+			_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+		} else if ((value & 0x01) == 0x00) {
+			_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
+			lo = value;
+			_wrmsr(USB_MSR_REG(USB_OHCI), hi, lo);
+
+			value &= 0xfffffff0;
+			hi = 0x40000000 | ((value & 0xff000000) >> 24);
+			lo = 0x000fffff | ((value & 0x00fff000) << 8);
+			_wrmsr(GLIU_MSR_REG(GLIU_P2D_BM3), hi, lo);
+		}
+		break;
+	case PCI_OHCI_INT_REG:
+		_rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo);
+		lo &= ~(0xf << PIC_YSEL_LOW_USB_SHIFT);
+		if (value)	/* enable all the usb interrupt in PIC */
+			lo |= (CS5536_USB_INTR << PIC_YSEL_LOW_USB_SHIFT);
+		_wrmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), hi, lo);
+		break;
+	default:
+		break;
+	}
+}
+
+u32 pci_ohci_read_reg(int reg)
+{
+	u32 conf_data = 0;
+	u32 hi, lo;
+
+	switch (reg) {
+	case PCI_VENDOR_ID:
+		conf_data =
+		    CFG_PCI_VENDOR_ID(CS5536_OHCI_DEVICE_ID, CS5536_VENDOR_ID);
+		break;
+	case PCI_COMMAND:
+		_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
+		if (hi & PCI_COMMAND_MASTER)
+			conf_data |= PCI_COMMAND_MASTER;
+		if (hi & PCI_COMMAND_MEMORY)
+			conf_data |= PCI_COMMAND_MEMORY;
+		break;
+	case PCI_STATUS:
+		conf_data |= PCI_STATUS_66MHZ;
+		conf_data |= PCI_STATUS_FAST_BACK;
+		_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+		if (lo & SB_PARE_ERR_FLAG)
+			conf_data |= PCI_STATUS_PARITY;
+		conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+		break;
+	case PCI_CLASS_REVISION:
+		_rdmsr(USB_MSR_REG(USB_CAP), &hi, &lo);
+		conf_data = lo & 0x000000ff;
+		conf_data |= (CS5536_OHCI_CLASS_CODE << 8);
+		break;
+	case PCI_CACHE_LINE_SIZE:
+		conf_data =
+		    CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
+					    PCI_NORMAL_LATENCY_TIMER);
+		break;
+	case PCI_BAR0_REG:
+		_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+		if (lo & SOFT_BAR_OHCI_FLAG) {
+			conf_data = CS5536_OHCI_RANGE |
+			    PCI_BASE_ADDRESS_SPACE_MEMORY;
+			lo &= ~SOFT_BAR_OHCI_FLAG;
+			_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+		} else {
+			_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
+			conf_data = lo & 0xffffff00;
+			conf_data &= ~0x0000000f;	/* 32bit mem */
+		}
+		break;
+	case PCI_CARDBUS_CIS:
+		conf_data = PCI_CARDBUS_CIS_POINTER;
+		break;
+	case PCI_SUBSYSTEM_VENDOR_ID:
+		conf_data =
+		    CFG_PCI_VENDOR_ID(CS5536_OHCI_SUB_ID, CS5536_SUB_VENDOR_ID);
+		break;
+	case PCI_ROM_ADDRESS:
+		conf_data = PCI_EXPANSION_ROM_BAR;
+		break;
+	case PCI_CAPABILITY_LIST:
+		conf_data = PCI_CAPLIST_USB_POINTER;
+		break;
+	case PCI_INTERRUPT_LINE:
+		conf_data =
+		    CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
+		break;
+	case PCI_OHCI_INT_REG:
+		_rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo);
+		if (((lo >> PIC_YSEL_LOW_USB_SHIFT) & 0xf) == CS5536_USB_INTR)
+			conf_data = 1;
+		break;
+	default:
+		break;
+	}
+
+	return conf_data;
+}
diff --git a/arch/mips/loongson2ef/common/cs5536/cs5536_pci.c b/arch/mips/loongson2ef/common/cs5536/cs5536_pci.c
new file mode 100644
index 0000000..202c89b
--- /dev/null
+++ b/arch/mips/loongson2ef/common/cs5536/cs5536_pci.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * read/write operation to the PCI config space of CS5536
+ *
+ * Copyright (C) 2007 Lemote, Inc.
+ * Author : jlliu, liujl@lemote.com
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ *	the Virtual Support Module(VSM) for virtulizing the PCI
+ *	configure space are defined in cs5536_modulename.c respectively,
+ *
+ *	after this virtulizing, user can access the PCI configure space
+ *	directly as a normal multi-function PCI device which follows
+ *	the PCI-2.2 spec.
+ */
+
+#include <linux/types.h>
+#include <cs5536/cs5536_pci.h>
+#include <cs5536/cs5536_vsm.h>
+
+enum {
+	CS5536_FUNC_START = -1,
+	CS5536_ISA_FUNC,
+	reserved_func,
+	CS5536_IDE_FUNC,
+	CS5536_ACC_FUNC,
+	CS5536_OHCI_FUNC,
+	CS5536_EHCI_FUNC,
+	CS5536_FUNC_END,
+};
+
+static const cs5536_pci_vsm_write vsm_conf_write[] = {
+	[CS5536_ISA_FUNC]	= pci_isa_write_reg,
+	[reserved_func]		= NULL,
+	[CS5536_IDE_FUNC]	= pci_ide_write_reg,
+	[CS5536_ACC_FUNC]	= pci_acc_write_reg,
+	[CS5536_OHCI_FUNC]	= pci_ohci_write_reg,
+	[CS5536_EHCI_FUNC]	= pci_ehci_write_reg,
+};
+
+static const cs5536_pci_vsm_read vsm_conf_read[] = {
+	[CS5536_ISA_FUNC]	= pci_isa_read_reg,
+	[reserved_func]		= NULL,
+	[CS5536_IDE_FUNC]	= pci_ide_read_reg,
+	[CS5536_ACC_FUNC]	= pci_acc_read_reg,
+	[CS5536_OHCI_FUNC]	= pci_ohci_read_reg,
+	[CS5536_EHCI_FUNC]	= pci_ehci_read_reg,
+};
+
+/*
+ * write to PCI config space and transfer it to MSR write.
+ */
+void cs5536_pci_conf_write4(int function, int reg, u32 value)
+{
+	if ((function <= CS5536_FUNC_START) || (function >= CS5536_FUNC_END))
+		return;
+	if ((reg < 0) || (reg > 0x100) || ((reg & 0x03) != 0))
+		return;
+
+	if (vsm_conf_write[function] != NULL)
+		vsm_conf_write[function](reg, value);
+}
+
+/*
+ * read PCI config space and transfer it to MSR access.
+ */
+u32 cs5536_pci_conf_read4(int function, int reg)
+{
+	u32 data = 0;
+
+	if ((function <= CS5536_FUNC_START) || (function >= CS5536_FUNC_END))
+		return 0;
+	if ((reg < 0) || ((reg & 0x03) != 0))
+		return 0;
+	if (reg > 0x100)
+		return 0xffffffff;
+
+	if (vsm_conf_read[function] != NULL)
+		data = vsm_conf_read[function](reg);
+
+	return data;
+}
diff --git a/arch/mips/loongson2ef/common/env.c b/arch/mips/loongson2ef/common/env.c
new file mode 100644
index 0000000..6f20bdf
--- /dev/null
+++ b/arch/mips/loongson2ef/common/env.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Based on Ocelot Linux port, which is
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ *
+ * Copyright 2003 ICT CAS
+ * Author: Michael Guo <guoyi@ict.ac.cn>
+ *
+ * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ *
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ */
+#include <linux/export.h>
+#include <asm/bootinfo.h>
+#include <asm/fw/fw.h>
+#include <loongson.h>
+
+u32 cpu_clock_freq;
+EXPORT_SYMBOL(cpu_clock_freq);
+
+void __init prom_init_env(void)
+{
+	/* pmon passes arguments in 32bit pointers */
+	unsigned int processor_id;
+
+	cpu_clock_freq = fw_getenvl("cpuclock");
+	memsize = fw_getenvl("memsize");
+	highmemsize = fw_getenvl("highmemsize");
+
+	if (memsize == 0)
+		memsize = 256;
+
+	pr_info("memsize=%u, highmemsize=%u\n", memsize, highmemsize);
+
+	if (cpu_clock_freq == 0) {
+		processor_id = (&current_cpu_data)->processor_id;
+		switch (processor_id & PRID_REV_MASK) {
+		case PRID_REV_LOONGSON2E:
+			cpu_clock_freq = 533080000;
+			break;
+		case PRID_REV_LOONGSON2F:
+			cpu_clock_freq = 797000000;
+			break;
+		default:
+			cpu_clock_freq = 100000000;
+			break;
+		}
+	}
+	pr_info("CpuClock = %u\n", cpu_clock_freq);
+}
diff --git a/arch/mips/loongson2ef/common/init.c b/arch/mips/loongson2ef/common/init.c
new file mode 100644
index 0000000..ce3f02f
--- /dev/null
+++ b/arch/mips/loongson2ef/common/init.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ */
+
+#include <linux/memblock.h>
+#include <asm/bootinfo.h>
+#include <asm/traps.h>
+#include <asm/smp-ops.h>
+#include <asm/cacheflush.h>
+#include <asm/fw/fw.h>
+
+#include <loongson.h>
+
+/* Loongson CPU address windows config space base address */
+unsigned long __maybe_unused _loongson_addrwincfg_base;
+
+static void __init mips_nmi_setup(void)
+{
+	void *base;
+	extern char except_vec_nmi[];
+
+	base = (void *)(CAC_BASE + 0x380);
+	memcpy(base, except_vec_nmi, 0x80);
+	flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
+}
+
+void __init prom_init(void)
+{
+#ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG
+	_loongson_addrwincfg_base = (unsigned long)
+		ioremap(LOONGSON_ADDRWINCFG_BASE, LOONGSON_ADDRWINCFG_SIZE);
+#endif
+
+	fw_init_cmdline();
+	prom_init_machtype();
+	prom_init_env();
+
+	/* init base address of io space */
+	set_io_port_base((unsigned long)
+		ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE));
+	prom_init_memory();
+
+	/*init the uart base address */
+	prom_init_uart_base();
+	board_nmi_handler_setup = mips_nmi_setup;
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
diff --git a/arch/mips/loongson2ef/common/irq.c b/arch/mips/loongson2ef/common/irq.c
new file mode 100644
index 0000000..0ea93c1
--- /dev/null
+++ b/arch/mips/loongson2ef/common/irq.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ */
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#include <loongson.h>
+/*
+ * the first level int-handler will jump here if it is a bonito irq
+ */
+void bonito_irqdispatch(void)
+{
+	u32 int_status;
+	int i;
+
+	/* workaround the IO dma problem: let cpu looping to allow DMA finish */
+	int_status = LOONGSON_INTISR;
+	while (int_status & (1 << 10)) {
+		udelay(1);
+		int_status = LOONGSON_INTISR;
+	}
+
+	/* Get pending sources, masked by current enables */
+	int_status = LOONGSON_INTISR & LOONGSON_INTEN;
+
+	if (int_status) {
+		i = __ffs(int_status);
+		do_IRQ(LOONGSON_IRQ_BASE + i);
+	}
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+	unsigned int pending;
+
+	pending = read_c0_cause() & read_c0_status() & ST0_IM;
+
+	/* machine-specific plat_irq_dispatch */
+	mach_irq_dispatch(pending);
+}
+
+void __init arch_init_irq(void)
+{
+	/*
+	 * Clear all of the interrupts while we change the able around a bit.
+	 * int-handler is not on bootstrap
+	 */
+	clear_c0_status(ST0_IM | ST0_BEV);
+
+	/* no steer */
+	LOONGSON_INTSTEER = 0;
+
+	/*
+	 * Mask out all interrupt by writing "1" to all bit position in
+	 * the interrupt reset reg.
+	 */
+	LOONGSON_INTENCLR = ~0;
+
+	/* machine specific irq init */
+	mach_init_irq();
+}
diff --git a/arch/mips/loongson2ef/common/machtype.c b/arch/mips/loongson2ef/common/machtype.c
new file mode 100644
index 0000000..82f6de4
--- /dev/null
+++ b/arch/mips/loongson2ef/common/machtype.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * Copyright (c) 2009 Zhang Le <r0bertz@gentoo.org>
+ */
+#include <linux/errno.h>
+#include <asm/bootinfo.h>
+
+#include <loongson.h>
+#include <machine.h>
+
+/* please ensure the length of the machtype string is less than 50 */
+#define MACHTYPE_LEN 50
+
+static const char *system_types[] = {
+	[MACH_LOONGSON_UNKNOWN]	= "unknown loongson machine",
+	[MACH_LEMOTE_FL2E]	= "lemote-fuloong-2e-box",
+	[MACH_LEMOTE_FL2F]	= "lemote-fuloong-2f-box",
+	[MACH_LEMOTE_ML2F7]	= "lemote-mengloong-2f-7inches",
+	[MACH_LEMOTE_YL2F89]	= "lemote-yeeloong-2f-8.9inches",
+	[MACH_DEXXON_GDIUM2F10]	= "dexxon-gdium-2f",
+	[MACH_LEMOTE_NAS]	= "lemote-nas-2f",
+	[MACH_LEMOTE_LL2F]	= "lemote-lynloong-2f",
+	[MACH_LOONGSON_END]	= NULL,
+};
+
+const char *get_system_type(void)
+{
+	return system_types[mips_machtype];
+}
+
+void __weak __init mach_prom_init_machtype(void)
+{
+}
+
+void __init prom_init_machtype(void)
+{
+	char *p, str[MACHTYPE_LEN + 1];
+	int machtype = MACH_LEMOTE_FL2E;
+
+	mips_machtype = LOONGSON_MACHTYPE;
+
+	p = strstr(arcs_cmdline, "machtype=");
+	if (!p) {
+		mach_prom_init_machtype();
+		return;
+	}
+	p += strlen("machtype=");
+	strncpy(str, p, MACHTYPE_LEN);
+	str[MACHTYPE_LEN] = '\0';
+	p = strstr(str, " ");
+	if (p)
+		*p = '\0';
+
+	for (; system_types[machtype]; machtype++)
+		if (strstr(system_types[machtype], str)) {
+			mips_machtype = machtype;
+			break;
+		}
+}
diff --git a/arch/mips/loongson2ef/common/mem.c b/arch/mips/loongson2ef/common/mem.c
new file mode 100644
index 0000000..057d58b
--- /dev/null
+++ b/arch/mips/loongson2ef/common/mem.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ */
+#include <linux/fs.h>
+#include <linux/fcntl.h>
+#include <linux/memblock.h>
+#include <linux/mm.h>
+
+#include <asm/bootinfo.h>
+
+#include <loongson.h>
+#include <mem.h>
+#include <pci.h>
+
+
+u32 memsize, highmemsize;
+
+void __init prom_init_memory(void)
+{
+	memblock_add(0x0, (memsize << 20));
+
+#ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG
+	{
+		int bit;
+
+		bit = fls(memsize + highmemsize);
+		if (bit != ffs(memsize + highmemsize))
+			bit += 20;
+		else
+			bit = bit + 20 - 1;
+
+		/* set cpu window3 to map CPU to DDR: 2G -> 2G */
+		LOONGSON_ADDRWIN_CPUTODDR(ADDRWIN_WIN3, 0x80000000ul,
+					  0x80000000ul, (1 << bit));
+		mmiowb();
+	}
+#endif /* !CONFIG_CPU_SUPPORTS_ADDRWINCFG */
+
+#ifdef CONFIG_64BIT
+	if (highmemsize > 0)
+		memblock_add(LOONGSON_HIGHMEM_START, highmemsize << 20);
+#endif /* !CONFIG_64BIT */
+}
+
+/* override of arch/mips/mm/cache.c: __uncached_access */
+int __uncached_access(struct file *file, unsigned long addr)
+{
+	if (file->f_flags & O_DSYNC)
+		return 1;
+
+	return addr >= __pa(high_memory) ||
+		((addr >= LOONGSON_MMIO_MEM_START) &&
+		 (addr < LOONGSON_MMIO_MEM_END));
+}
diff --git a/arch/mips/loongson2ef/common/pci.c b/arch/mips/loongson2ef/common/pci.c
new file mode 100644
index 0000000..2009169
--- /dev/null
+++ b/arch/mips/loongson2ef/common/pci.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2007 Lemote, Inc. & Institute of Computing Technology
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ */
+#include <linux/pci.h>
+
+#include <pci.h>
+#include <loongson.h>
+
+static struct resource loongson_pci_mem_resource = {
+	.name	= "pci memory space",
+	.start	= LOONGSON_PCI_MEM_START,
+	.end	= LOONGSON_PCI_MEM_END,
+	.flags	= IORESOURCE_MEM,
+};
+
+static struct resource loongson_pci_io_resource = {
+	.name	= "pci io space",
+	.start	= LOONGSON_PCI_IO_START,
+	.end	= IO_SPACE_LIMIT,
+	.flags	= IORESOURCE_IO,
+};
+
+static struct pci_controller  loongson_pci_controller = {
+	.pci_ops	= &loongson_pci_ops,
+	.io_resource	= &loongson_pci_io_resource,
+	.mem_resource	= &loongson_pci_mem_resource,
+	.mem_offset	= 0x00000000UL,
+	.io_offset	= 0x00000000UL,
+};
+
+static void __init setup_pcimap(void)
+{
+	/*
+	 * local to PCI mapping for CPU accessing PCI space
+	 * CPU address space [256M,448M] is window for accessing pci space
+	 * we set pcimap_lo[0,1,2] to map it to pci space[0M,64M], [320M,448M]
+	 *
+	 * pcimap: PCI_MAP2  PCI_Mem_Lo2 PCI_Mem_Lo1 PCI_Mem_Lo0
+	 *	     [<2G]   [384M,448M] [320M,384M] [0M,64M]
+	 */
+	LOONGSON_PCIMAP = LOONGSON_PCIMAP_PCIMAP_2 |
+		LOONGSON_PCIMAP_WIN(2, LOONGSON_PCILO2_BASE) |
+		LOONGSON_PCIMAP_WIN(1, LOONGSON_PCILO1_BASE) |
+		LOONGSON_PCIMAP_WIN(0, 0);
+
+	/*
+	 * PCI-DMA to local mapping: [2G,2G+256M] -> [0M,256M]
+	 */
+	LOONGSON_PCIBASE0 = 0x80000000ul;   /* base: 2G -> mmap: 0M */
+	/* size: 256M, burst transmission, pre-fetch enable, 64bit */
+	LOONGSON_PCI_HIT0_SEL_L = 0xc000000cul;
+	LOONGSON_PCI_HIT0_SEL_H = 0xfffffffful;
+	LOONGSON_PCI_HIT1_SEL_L = 0x00000006ul; /* set this BAR as invalid */
+	LOONGSON_PCI_HIT1_SEL_H = 0x00000000ul;
+	LOONGSON_PCI_HIT2_SEL_L = 0x00000006ul; /* set this BAR as invalid */
+	LOONGSON_PCI_HIT2_SEL_H = 0x00000000ul;
+
+	/* avoid deadlock of PCI reading/writing lock operation */
+	LOONGSON_PCI_ISR4C = 0xd2000001ul;
+
+	/* can not change gnt to break pci transfer when device's gnt not
+	deassert for some broken device */
+	LOONGSON_PXARB_CFG = 0x00fe0105ul;
+
+#ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG
+	/*
+	 * set cpu addr window2 to map CPU address space to PCI address space
+	 */
+	LOONGSON_ADDRWIN_CPUTOPCI(ADDRWIN_WIN2, LOONGSON_CPU_MEM_SRC,
+		LOONGSON_PCI_MEM_DST, MMAP_CPUTOPCI_SIZE);
+#endif
+}
+
+extern int sbx00_acpi_init(void);
+
+static int __init pcibios_init(void)
+{
+	setup_pcimap();
+
+	loongson_pci_controller.io_map_base = mips_io_port_base;
+	register_pci_controller(&loongson_pci_controller);
+
+
+	return 0;
+}
+
+arch_initcall(pcibios_init);
diff --git a/arch/mips/loongson2ef/common/platform.c b/arch/mips/loongson2ef/common/platform.c
new file mode 100644
index 0000000..0084820
--- /dev/null
+++ b/arch/mips/loongson2ef/common/platform.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ */
+
+#include <linux/err.h>
+#include <linux/smp.h>
+#include <linux/platform_device.h>
+
+static struct platform_device loongson2_cpufreq_device = {
+	.name = "loongson2_cpufreq",
+	.id = -1,
+};
+
+static int __init loongson2_cpufreq_init(void)
+{
+	struct cpuinfo_mips *c = &current_cpu_data;
+
+	/* Only 2F revision and it's successors support CPUFreq */
+	if ((c->processor_id & PRID_REV_MASK) >= PRID_REV_LOONGSON2F)
+		return platform_device_register(&loongson2_cpufreq_device);
+
+	return -ENODEV;
+}
+
+arch_initcall(loongson2_cpufreq_init);
diff --git a/arch/mips/loongson2ef/common/pm.c b/arch/mips/loongson2ef/common/pm.c
new file mode 100644
index 0000000..bcb7ae9
--- /dev/null
+++ b/arch/mips/loongson2ef/common/pm.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * loongson-specific suspend support
+ *
+ *  Copyright (C) 2009 Lemote Inc.
+ *  Author: Wu Zhangjin <wuzhangjin@gmail.com>
+ */
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+
+#include <asm/i8259.h>
+#include <asm/mipsregs.h>
+
+#include <loongson.h>
+
+static unsigned int __maybe_unused cached_master_mask;	/* i8259A */
+static unsigned int __maybe_unused cached_slave_mask;
+static unsigned int __maybe_unused cached_bonito_irq_mask; /* bonito */
+
+void arch_suspend_disable_irqs(void)
+{
+	/* disable all mips events */
+	local_irq_disable();
+
+#ifdef CONFIG_I8259
+	/* disable all events of i8259A */
+	cached_slave_mask = inb(PIC_SLAVE_IMR);
+	cached_master_mask = inb(PIC_MASTER_IMR);
+
+	outb(0xff, PIC_SLAVE_IMR);
+	inb(PIC_SLAVE_IMR);
+	outb(0xff, PIC_MASTER_IMR);
+	inb(PIC_MASTER_IMR);
+#endif
+	/* disable all events of bonito */
+	cached_bonito_irq_mask = LOONGSON_INTEN;
+	LOONGSON_INTENCLR = 0xffff;
+	(void)LOONGSON_INTENCLR;
+}
+
+void arch_suspend_enable_irqs(void)
+{
+	/* enable all mips events */
+	local_irq_enable();
+#ifdef CONFIG_I8259
+	/* only enable the cached events of i8259A */
+	outb(cached_slave_mask, PIC_SLAVE_IMR);
+	outb(cached_master_mask, PIC_MASTER_IMR);
+#endif
+	/* enable all cached events of bonito */
+	LOONGSON_INTENSET = cached_bonito_irq_mask;
+	(void)LOONGSON_INTENSET;
+}
+
+/*
+ * Setup the board-specific events for waking up loongson from wait mode
+ */
+void __weak setup_wakeup_events(void)
+{
+}
+
+/*
+ * Check wakeup events
+ */
+int __weak wakeup_loongson(void)
+{
+	return 1;
+}
+
+/*
+ * If the events are really what we want to wakeup the CPU, wake it up
+ * otherwise put the CPU asleep again.
+ */
+static void wait_for_wakeup_events(void)
+{
+	while (!wakeup_loongson())
+		writel(readl(LOONGSON_CHIPCFG) & ~0x7, LOONGSON_CHIPCFG);
+}
+
+/*
+ * Stop all perf counters
+ *
+ * $24 is the control register of Loongson perf counter
+ */
+static inline void stop_perf_counters(void)
+{
+	__write_64bit_c0_register($24, 0, 0);
+}
+
+
+static void loongson_suspend_enter(void)
+{
+	unsigned int cached_cpu_freq;
+
+	/* setup wakeup events via enabling the IRQs */
+	setup_wakeup_events();
+
+	stop_perf_counters();
+
+	cached_cpu_freq = readl(LOONGSON_CHIPCFG);
+
+	/* Put CPU into wait mode */
+	writel(readl(LOONGSON_CHIPCFG) & ~0x7, LOONGSON_CHIPCFG);
+
+	/* wait for the given events to wakeup cpu from wait mode */
+	wait_for_wakeup_events();
+
+	writel(cached_cpu_freq, LOONGSON_CHIPCFG);
+
+	mmiowb();
+}
+
+void __weak mach_suspend(void)
+{
+}
+
+void __weak mach_resume(void)
+{
+}
+
+static int loongson_pm_enter(suspend_state_t state)
+{
+	mach_suspend();
+
+	/* processor specific suspend */
+	loongson_suspend_enter();
+
+	mach_resume();
+
+	return 0;
+}
+
+static int loongson_pm_valid_state(suspend_state_t state)
+{
+	switch (state) {
+	case PM_SUSPEND_ON:
+	case PM_SUSPEND_STANDBY:
+	case PM_SUSPEND_MEM:
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+
+static const struct platform_suspend_ops loongson_pm_ops = {
+	.valid	= loongson_pm_valid_state,
+	.enter	= loongson_pm_enter,
+};
+
+static int __init loongson_pm_init(void)
+{
+	suspend_set_ops(&loongson_pm_ops);
+
+	return 0;
+}
+arch_initcall(loongson_pm_init);
diff --git a/arch/mips/loongson2ef/common/reset.c b/arch/mips/loongson2ef/common/reset.c
new file mode 100644
index 0000000..e49c406
--- /dev/null
+++ b/arch/mips/loongson2ef/common/reset.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * Copyright (C) 2007 Lemote, Inc. & Institute of Computing Technology
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Zhangjin Wu, wuzhangjin@gmail.com
+ */
+#include <linux/init.h>
+#include <linux/pm.h>
+
+#include <asm/idle.h>
+#include <asm/reboot.h>
+
+#include <loongson.h>
+
+static inline void loongson_reboot(void)
+{
+#ifndef CONFIG_CPU_JUMP_WORKAROUNDS
+	((void (*)(void))ioremap(LOONGSON_BOOT_BASE, 4)) ();
+#else
+	void (*func)(void);
+
+	func = (void *)ioremap(LOONGSON_BOOT_BASE, 4);
+
+	__asm__ __volatile__(
+	"	.set	noat						\n"
+	"	jr	%[func]						\n"
+	"	.set	at						\n"
+	: /* No outputs */
+	: [func] "r" (func));
+#endif
+}
+
+static void loongson_restart(char *command)
+{
+	/* do preparation for reboot */
+	mach_prepare_reboot();
+
+	/* reboot via jumping to boot base address */
+	loongson_reboot();
+}
+
+static void loongson_poweroff(void)
+{
+	mach_prepare_shutdown();
+
+	/*
+	 * It needs a wait loop here, but mips/kernel/reset.c already calls
+	 * a generic delay loop, machine_hang(), so simply return.
+	 */
+	return;
+}
+
+static void loongson_halt(void)
+{
+	pr_notice("\n\n** You can safely turn off the power now **\n\n");
+	while (1) {
+		if (cpu_wait)
+			cpu_wait();
+	}
+}
+
+static int __init mips_reboot_setup(void)
+{
+	_machine_restart = loongson_restart;
+	_machine_halt = loongson_halt;
+	pm_power_off = loongson_poweroff;
+
+	return 0;
+}
+
+arch_initcall(mips_reboot_setup);
diff --git a/arch/mips/loongson2ef/common/rtc.c b/arch/mips/loongson2ef/common/rtc.c
new file mode 100644
index 0000000..8d7628c
--- /dev/null
+++ b/arch/mips/loongson2ef/common/rtc.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Lemote Fuloong platform support
+ *
+ *  Copyright(c) 2010 Arnaud Patard <apatard@mandriva.com>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mc146818rtc.h>
+
+static struct resource loongson_rtc_resources[] = {
+	{
+		.start	= RTC_PORT(0),
+		.end	= RTC_PORT(1),
+		.flags	= IORESOURCE_IO,
+	}, {
+		.start	= RTC_IRQ,
+		.end	= RTC_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device loongson_rtc_device = {
+	.name		= "rtc_cmos",
+	.id		= -1,
+	.resource	= loongson_rtc_resources,
+	.num_resources	= ARRAY_SIZE(loongson_rtc_resources),
+};
+
+
+static int __init loongson_rtc_platform_init(void)
+{
+	platform_device_register(&loongson_rtc_device);
+	return 0;
+}
+
+device_initcall(loongson_rtc_platform_init);
diff --git a/arch/mips/loongson2ef/common/serial.c b/arch/mips/loongson2ef/common/serial.c
new file mode 100644
index 0000000..ac4f6e3
--- /dev/null
+++ b/arch/mips/loongson2ef/common/serial.c
@@ -0,0 +1,86 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org)
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Yan hua (yanhua@lemote.com)
+ * Author: Wu Zhangjin (wuzhangjin@gmail.com)
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/serial_8250.h>
+
+#include <asm/bootinfo.h>
+
+#include <loongson.h>
+#include <machine.h>
+
+#define PORT(int, clk)			\
+{								\
+	.irq		= int,					\
+	.uartclk	= clk,					\
+	.iotype		= UPIO_PORT,				\
+	.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,	\
+	.regshift	= 0,					\
+}
+
+#define PORT_M(int, clk)				\
+{								\
+	.irq		= MIPS_CPU_IRQ_BASE + (int),		\
+	.uartclk	= clk,					\
+	.iotype		= UPIO_MEM,				\
+	.membase	= (void __iomem *)NULL,			\
+	.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,	\
+	.regshift	= 0,					\
+}
+
+static struct plat_serial8250_port uart8250_data[MACH_LOONGSON_END + 1] = {
+	[MACH_LOONGSON_UNKNOWN]	= {},
+	[MACH_LEMOTE_FL2E]	= PORT(4, 1843200),
+	[MACH_LEMOTE_FL2F]	= PORT(3, 1843200),
+	[MACH_LEMOTE_ML2F7]	= PORT_M(3, 3686400),
+	[MACH_LEMOTE_YL2F89]	= PORT_M(3, 3686400),
+	[MACH_DEXXON_GDIUM2F10]	= PORT_M(3, 3686400),
+	[MACH_LEMOTE_NAS]	= PORT_M(3, 3686400),
+	[MACH_LEMOTE_LL2F]	= PORT(3, 1843200),
+	[MACH_LOONGSON_END]	= {},
+};
+
+static struct platform_device uart8250_device = {
+	.name = "serial8250",
+	.id = PLAT8250_DEV_PLATFORM,
+};
+
+static int __init serial_init(void)
+{
+	unsigned char iotype;
+
+	iotype = uart8250_data[mips_machtype].iotype;
+
+	if (UPIO_MEM == iotype) {
+		uart8250_data[mips_machtype].mapbase =
+			loongson_uart_base;
+		uart8250_data[mips_machtype].membase =
+			(void __iomem *)_loongson_uart_base;
+	}
+	else if (UPIO_PORT == iotype)
+		uart8250_data[mips_machtype].iobase =
+			loongson_uart_base - LOONGSON_PCIIO_BASE;
+
+	memset(&uart8250_data[mips_machtype + 1], 0,
+			sizeof(struct plat_serial8250_port));
+	uart8250_device.dev.platform_data = &uart8250_data[mips_machtype];
+
+	return platform_device_register(&uart8250_device);
+}
+module_init(serial_init);
+
+static void __exit serial_exit(void)
+{
+	platform_device_unregister(&uart8250_device);
+}
+module_exit(serial_exit);
diff --git a/arch/mips/loongson2ef/common/setup.c b/arch/mips/loongson2ef/common/setup.c
new file mode 100644
index 0000000..4fd27f4
--- /dev/null
+++ b/arch/mips/loongson2ef/common/setup.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ */
+#include <linux/export.h>
+#include <linux/init.h>
+
+#include <asm/wbflush.h>
+#include <asm/bootinfo.h>
+
+#include <loongson.h>
+
+static void wbflush_loongson(void)
+{
+	asm(".set\tpush\n\t"
+	    ".set\tnoreorder\n\t"
+	    ".set mips3\n\t"
+	    "sync\n\t"
+	    "nop\n\t"
+	    ".set\tpop\n\t"
+	    ".set mips0\n\t");
+}
+
+void (*__wbflush)(void) = wbflush_loongson;
+EXPORT_SYMBOL(__wbflush);
+
+void __init plat_mem_setup(void)
+{
+}
diff --git a/arch/mips/loongson2ef/common/time.c b/arch/mips/loongson2ef/common/time.c
new file mode 100644
index 0000000..585741a
--- /dev/null
+++ b/arch/mips/loongson2ef/common/time.c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2007 Lemote, Inc. & Institute of Computing Technology
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ *
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ */
+#include <asm/mc146818-time.h>
+#include <asm/time.h>
+#include <asm/hpet.h>
+
+#include <loongson.h>
+#include <cs5536/cs5536_mfgpt.h>
+
+void __init plat_time_init(void)
+{
+	/* setup mips r4k timer */
+	mips_hpt_frequency = cpu_clock_freq / 2;
+
+	setup_mfgpt0_timer();
+}
+
+void read_persistent_clock64(struct timespec64 *ts)
+{
+	ts->tv_sec = mc146818_get_cmos_time();
+	ts->tv_nsec = 0;
+}
diff --git a/arch/mips/loongson2ef/common/uart_base.c b/arch/mips/loongson2ef/common/uart_base.c
new file mode 100644
index 0000000..522bea6
--- /dev/null
+++ b/arch/mips/loongson2ef/common/uart_base.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ */
+
+#include <linux/export.h>
+#include <asm/bootinfo.h>
+#include <asm/setup.h>
+
+#include <loongson.h>
+
+/* raw */
+unsigned long loongson_uart_base;
+/* ioremapped */
+unsigned long _loongson_uart_base;
+
+EXPORT_SYMBOL(loongson_uart_base);
+EXPORT_SYMBOL(_loongson_uart_base);
+
+void prom_init_loongson_uart_base(void)
+{
+	switch (mips_machtype) {
+	case MACH_LEMOTE_FL2E:
+		loongson_uart_base = LOONGSON_PCIIO_BASE + 0x3f8;
+		break;
+	case MACH_LEMOTE_FL2F:
+	case MACH_LEMOTE_LL2F:
+		loongson_uart_base = LOONGSON_PCIIO_BASE + 0x2f8;
+		break;
+	case MACH_LEMOTE_ML2F7:
+	case MACH_LEMOTE_YL2F89:
+	case MACH_DEXXON_GDIUM2F10:
+	case MACH_LEMOTE_NAS:
+	default:
+		/* The CPU provided serial port (LPC) */
+		loongson_uart_base = LOONGSON_LIO1_BASE + 0x3f8;
+		break;
+	}
+
+	_loongson_uart_base = TO_UNCAC(loongson_uart_base);
+	setup_8250_early_printk_port(_loongson_uart_base, 0, 1024);
+}
diff --git a/arch/mips/loongson2ef/fuloong-2e/Makefile b/arch/mips/loongson2ef/fuloong-2e/Makefile
new file mode 100644
index 0000000..bb58edb
--- /dev/null
+++ b/arch/mips/loongson2ef/fuloong-2e/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for Lemote Fuloong2e mini-PC board.
+#
+
+obj-y += irq.o reset.o dma.o
diff --git a/arch/mips/loongson2ef/fuloong-2e/dma.c b/arch/mips/loongson2ef/fuloong-2e/dma.c
new file mode 100644
index 0000000..cea167d
--- /dev/null
+++ b/arch/mips/loongson2ef/fuloong-2e/dma.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/dma-direct.h>
+
+dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+	return paddr | 0x80000000;
+}
+
+phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dma_addr)
+{
+	return dma_addr & 0x7fffffff;
+}
diff --git a/arch/mips/loongson2ef/fuloong-2e/irq.c b/arch/mips/loongson2ef/fuloong-2e/irq.c
new file mode 100644
index 0000000..305aa2e
--- /dev/null
+++ b/arch/mips/loongson2ef/fuloong-2e/irq.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ */
+#include <linux/interrupt.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/i8259.h>
+
+#include <loongson.h>
+
+static void i8259_irqdispatch(void)
+{
+	int irq;
+
+	irq = i8259_irq();
+	if (irq >= 0)
+		do_IRQ(irq);
+	else
+		spurious_interrupt();
+}
+
+asmlinkage void mach_irq_dispatch(unsigned int pending)
+{
+	if (pending & CAUSEF_IP7)
+		do_IRQ(MIPS_CPU_IRQ_BASE + 7);
+	else if (pending & CAUSEF_IP6) /* perf counter loverflow */
+		do_perfcnt_IRQ();
+	else if (pending & CAUSEF_IP5)
+		i8259_irqdispatch();
+	else if (pending & CAUSEF_IP2)
+		bonito_irqdispatch();
+	else
+		spurious_interrupt();
+}
+
+void __init mach_init_irq(void)
+{
+	int irq;
+
+	/* init all controller
+	 *   0-15	  ------> i8259 interrupt
+	 *   16-23	  ------> mips cpu interrupt
+	 *   32-63	  ------> bonito irq
+	 */
+
+	/* most bonito irq should be level triggered */
+	LOONGSON_INTEDGE = LOONGSON_ICU_SYSTEMERR | LOONGSON_ICU_MASTERERR |
+	    LOONGSON_ICU_RETRYERR | LOONGSON_ICU_MBOXES;
+
+	/* Sets the first-level interrupt dispatcher. */
+	mips_cpu_irq_init();
+	init_i8259_irqs();
+	bonito_irq_init();
+
+	/* bonito irq at IP2 */
+	irq = MIPS_CPU_IRQ_BASE + 2;
+	if (request_irq(irq, no_action, IRQF_NO_THREAD, "cascade", NULL))
+		pr_err("Failed to request irq %d (cascade)\n", irq);
+	/* 8259 irq at IP5 */
+	irq = MIPS_CPU_IRQ_BASE + 5;
+	if (request_irq(irq, no_action, IRQF_NO_THREAD, "cascade", NULL))
+		pr_err("Failed to request irq %d (cascade)\n", irq);
+}
diff --git a/arch/mips/loongson2ef/fuloong-2e/reset.c b/arch/mips/loongson2ef/fuloong-2e/reset.c
new file mode 100644
index 0000000..8273de1
--- /dev/null
+++ b/arch/mips/loongson2ef/fuloong-2e/reset.c
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Board-specific reboot/shutdown routines
+ * Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca>
+ *
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ */
+
+#include <loongson.h>
+
+void mach_prepare_reboot(void)
+{
+	LOONGSON_GENCFG &= ~(1 << 2);
+	LOONGSON_GENCFG |= (1 << 2);
+}
+
+void mach_prepare_shutdown(void)
+{
+}
diff --git a/arch/mips/loongson2ef/lemote-2f/Makefile b/arch/mips/loongson2ef/lemote-2f/Makefile
new file mode 100644
index 0000000..881a0ec
--- /dev/null
+++ b/arch/mips/loongson2ef/lemote-2f/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for lemote loongson2f family machines
+#
+
+obj-y += clock.o machtype.o irq.o reset.o dma.o ec_kb3310b.o
+
+#
+# Suspend Support
+#
+
+obj-$(CONFIG_SUSPEND) += pm.o
diff --git a/arch/mips/loongson2ef/lemote-2f/clock.c b/arch/mips/loongson2ef/lemote-2f/clock.c
new file mode 100644
index 0000000..850b6b9
--- /dev/null
+++ b/arch/mips/loongson2ef/lemote-2f/clock.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2006 - 2008 Lemote Inc. & Institute of Computing Technology
+ * Author: Yanhua, yanh@lemote.com
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/cpufreq.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+
+#include <asm/mach-loongson2ef/loongson.h>
+
+enum {
+	DC_ZERO, DC_25PT = 2, DC_37PT, DC_50PT, DC_62PT, DC_75PT,
+	DC_87PT, DC_DISABLE, DC_RESV
+};
+
+struct cpufreq_frequency_table loongson2_clockmod_table[] = {
+	{0, DC_RESV, CPUFREQ_ENTRY_INVALID},
+	{0, DC_ZERO, CPUFREQ_ENTRY_INVALID},
+	{0, DC_25PT, 0},
+	{0, DC_37PT, 0},
+	{0, DC_50PT, 0},
+	{0, DC_62PT, 0},
+	{0, DC_75PT, 0},
+	{0, DC_87PT, 0},
+	{0, DC_DISABLE, 0},
+	{0, DC_RESV, CPUFREQ_TABLE_END},
+};
+EXPORT_SYMBOL_GPL(loongson2_clockmod_table);
+
+int loongson2_cpu_set_rate(unsigned long rate_khz)
+{
+	struct cpufreq_frequency_table *pos;
+	int regval;
+
+	cpufreq_for_each_valid_entry(pos, loongson2_clockmod_table)
+		if (rate_khz == pos->frequency)
+			break;
+	if (rate_khz != pos->frequency)
+		return -ENOTSUPP;
+
+	regval = readl(LOONGSON_CHIPCFG);
+	regval = (regval & ~0x7) | (pos->driver_data - 1);
+	writel(regval, LOONGSON_CHIPCFG);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(loongson2_cpu_set_rate);
diff --git a/arch/mips/loongson2ef/lemote-2f/dma.c b/arch/mips/loongson2ef/lemote-2f/dma.c
new file mode 100644
index 0000000..3c9e994
--- /dev/null
+++ b/arch/mips/loongson2ef/lemote-2f/dma.c
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/dma-direct.h>
+
+dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+	return paddr | 0x80000000;
+}
+
+phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dma_addr)
+{
+	if (dma_addr > 0x8fffffff)
+		return dma_addr;
+	return dma_addr & 0x0fffffff;
+}
diff --git a/arch/mips/loongson2ef/lemote-2f/ec_kb3310b.c b/arch/mips/loongson2ef/lemote-2f/ec_kb3310b.c
new file mode 100644
index 0000000..d138220
--- /dev/null
+++ b/arch/mips/loongson2ef/lemote-2f/ec_kb3310b.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Basic KB3310B Embedded Controller support for the YeeLoong 2F netbook
+ *
+ *  Copyright (C) 2008 Lemote Inc.
+ *  Author: liujl <liujl@lemote.com>, 2008-04-20
+ */
+
+#include <linux/io.h>
+#include <linux/export.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+
+#include "ec_kb3310b.h"
+
+static DEFINE_SPINLOCK(index_access_lock);
+static DEFINE_SPINLOCK(port_access_lock);
+
+unsigned char ec_read(unsigned short addr)
+{
+	unsigned char value;
+	unsigned long flags;
+
+	spin_lock_irqsave(&index_access_lock, flags);
+	outb((addr & 0xff00) >> 8, EC_IO_PORT_HIGH);
+	outb((addr & 0x00ff), EC_IO_PORT_LOW);
+	value = inb(EC_IO_PORT_DATA);
+	spin_unlock_irqrestore(&index_access_lock, flags);
+
+	return value;
+}
+EXPORT_SYMBOL_GPL(ec_read);
+
+void ec_write(unsigned short addr, unsigned char val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&index_access_lock, flags);
+	outb((addr & 0xff00) >> 8, EC_IO_PORT_HIGH);
+	outb((addr & 0x00ff), EC_IO_PORT_LOW);
+	outb(val, EC_IO_PORT_DATA);
+	/*  flush the write action */
+	inb(EC_IO_PORT_DATA);
+	spin_unlock_irqrestore(&index_access_lock, flags);
+}
+EXPORT_SYMBOL_GPL(ec_write);
+
+/*
+ * This function is used for EC command writes and corresponding status queries.
+ */
+int ec_query_seq(unsigned char cmd)
+{
+	int timeout;
+	unsigned char status;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&port_access_lock, flags);
+
+	/* make chip goto reset mode */
+	udelay(EC_REG_DELAY);
+	outb(cmd, EC_CMD_PORT);
+	udelay(EC_REG_DELAY);
+
+	/* check if the command is received by ec */
+	timeout = EC_CMD_TIMEOUT;
+	status = inb(EC_STS_PORT);
+	while (timeout-- && (status & (1 << 1))) {
+		status = inb(EC_STS_PORT);
+		udelay(EC_REG_DELAY);
+	}
+
+	spin_unlock_irqrestore(&port_access_lock, flags);
+
+	if (timeout <= 0) {
+		printk(KERN_ERR "%s: deadable error : timeout...\n", __func__);
+		ret = -EINVAL;
+	} else
+		printk(KERN_INFO
+			   "(%x/%d)ec issued command %d status : 0x%x\n",
+			   timeout, EC_CMD_TIMEOUT - timeout, cmd, status);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ec_query_seq);
+
+/*
+ * Send query command to EC to get the proper event number
+ */
+int ec_query_event_num(void)
+{
+	return ec_query_seq(CMD_GET_EVENT_NUM);
+}
+EXPORT_SYMBOL(ec_query_event_num);
+
+/*
+ * Get event number from EC
+ *
+ * NOTE: This routine must follow the query_event_num function in the
+ * interrupt.
+ */
+int ec_get_event_num(void)
+{
+	int timeout = 100;
+	unsigned char value;
+	unsigned char status;
+
+	udelay(EC_REG_DELAY);
+	status = inb(EC_STS_PORT);
+	udelay(EC_REG_DELAY);
+	while (timeout-- && !(status & (1 << 0))) {
+		status = inb(EC_STS_PORT);
+		udelay(EC_REG_DELAY);
+	}
+	if (timeout <= 0) {
+		pr_info("%s: get event number timeout.\n", __func__);
+
+		return -EINVAL;
+	}
+	value = inb(EC_DAT_PORT);
+	udelay(EC_REG_DELAY);
+
+	return value;
+}
+EXPORT_SYMBOL(ec_get_event_num);
diff --git a/arch/mips/loongson2ef/lemote-2f/ec_kb3310b.h b/arch/mips/loongson2ef/lemote-2f/ec_kb3310b.h
new file mode 100644
index 0000000..aecdbc9
--- /dev/null
+++ b/arch/mips/loongson2ef/lemote-2f/ec_kb3310b.h
@@ -0,0 +1,184 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * KB3310B Embedded Controller
+ *
+ *  Copyright (C) 2008 Lemote Inc.
+ *  Author: liujl <liujl@lemote.com>, 2008-03-14
+ */
+
+#ifndef _EC_KB3310B_H
+#define _EC_KB3310B_H
+
+extern unsigned char ec_read(unsigned short addr);
+extern void ec_write(unsigned short addr, unsigned char val);
+extern int ec_query_seq(unsigned char cmd);
+extern int ec_query_event_num(void);
+extern int ec_get_event_num(void);
+
+typedef int (*sci_handler) (int status);
+extern sci_handler yeeloong_report_lid_status;
+
+#define SCI_IRQ_NUM 0x0A
+
+/*
+ * The following registers are determined by the EC index configuration.
+ * 1, fill the PORT_HIGH as EC register high part.
+ * 2, fill the PORT_LOW as EC register low part.
+ * 3, fill the PORT_DATA as EC register write data or get the data from it.
+ */
+#define EC_IO_PORT_HIGH 0x0381
+#define EC_IO_PORT_LOW	0x0382
+#define EC_IO_PORT_DATA 0x0383
+
+/*
+ * EC delay time is 500us for register and status access
+ */
+#define EC_REG_DELAY	500	/* unit : us */
+#define EC_CMD_TIMEOUT	0x1000
+
+/*
+ * EC access port for SCI communication
+ */
+#define EC_CMD_PORT		0x66
+#define EC_STS_PORT		0x66
+#define EC_DAT_PORT		0x62
+#define CMD_INIT_IDLE_MODE	0xdd
+#define CMD_EXIT_IDLE_MODE	0xdf
+#define CMD_INIT_RESET_MODE	0xd8
+#define CMD_REBOOT_SYSTEM	0x8c
+#define CMD_GET_EVENT_NUM	0x84
+#define CMD_PROGRAM_PIECE	0xda
+
+/* temperature & fan registers */
+#define REG_TEMPERATURE_VALUE	0xF458
+#define REG_FAN_AUTO_MAN_SWITCH 0xF459
+#define BIT_FAN_AUTO		0
+#define BIT_FAN_MANUAL		1
+#define REG_FAN_CONTROL		0xF4D2
+#define BIT_FAN_CONTROL_ON	(1 << 0)
+#define BIT_FAN_CONTROL_OFF	(0 << 0)
+#define REG_FAN_STATUS		0xF4DA
+#define BIT_FAN_STATUS_ON	(1 << 0)
+#define BIT_FAN_STATUS_OFF	(0 << 0)
+#define REG_FAN_SPEED_HIGH	0xFE22
+#define REG_FAN_SPEED_LOW	0xFE23
+#define REG_FAN_SPEED_LEVEL	0xF4CC
+/* fan speed divider */
+#define FAN_SPEED_DIVIDER	480000	/* (60*1000*1000/62.5/2)*/
+
+/* battery registers */
+#define REG_BAT_DESIGN_CAP_HIGH		0xF77D
+#define REG_BAT_DESIGN_CAP_LOW		0xF77E
+#define REG_BAT_FULLCHG_CAP_HIGH	0xF780
+#define REG_BAT_FULLCHG_CAP_LOW		0xF781
+#define REG_BAT_DESIGN_VOL_HIGH		0xF782
+#define REG_BAT_DESIGN_VOL_LOW		0xF783
+#define REG_BAT_CURRENT_HIGH		0xF784
+#define REG_BAT_CURRENT_LOW		0xF785
+#define REG_BAT_VOLTAGE_HIGH		0xF786
+#define REG_BAT_VOLTAGE_LOW		0xF787
+#define REG_BAT_TEMPERATURE_HIGH	0xF788
+#define REG_BAT_TEMPERATURE_LOW		0xF789
+#define REG_BAT_RELATIVE_CAP_HIGH	0xF492
+#define REG_BAT_RELATIVE_CAP_LOW	0xF493
+#define REG_BAT_VENDOR			0xF4C4
+#define FLAG_BAT_VENDOR_SANYO		0x01
+#define FLAG_BAT_VENDOR_SIMPLO		0x02
+#define REG_BAT_CELL_COUNT		0xF4C6
+#define FLAG_BAT_CELL_3S1P		0x03
+#define FLAG_BAT_CELL_3S2P		0x06
+#define REG_BAT_CHARGE			0xF4A2
+#define FLAG_BAT_CHARGE_DISCHARGE	0x01
+#define FLAG_BAT_CHARGE_CHARGE		0x02
+#define FLAG_BAT_CHARGE_ACPOWER		0x00
+#define REG_BAT_STATUS			0xF4B0
+#define BIT_BAT_STATUS_LOW		(1 << 5)
+#define BIT_BAT_STATUS_DESTROY		(1 << 2)
+#define BIT_BAT_STATUS_FULL		(1 << 1)
+#define BIT_BAT_STATUS_IN		(1 << 0)
+#define REG_BAT_CHARGE_STATUS		0xF4B1
+#define BIT_BAT_CHARGE_STATUS_OVERTEMP	(1 << 2)
+#define BIT_BAT_CHARGE_STATUS_PRECHG	(1 << 1)
+#define REG_BAT_STATE			0xF482
+#define BIT_BAT_STATE_CHARGING		(1 << 1)
+#define BIT_BAT_STATE_DISCHARGING	(1 << 0)
+#define REG_BAT_POWER			0xF440
+#define BIT_BAT_POWER_S3		(1 << 2)
+#define BIT_BAT_POWER_ON		(1 << 1)
+#define BIT_BAT_POWER_ACIN		(1 << 0)
+
+/* other registers */
+/* Audio: rd/wr */
+#define REG_AUDIO_VOLUME	0xF46C
+#define REG_AUDIO_MUTE		0xF4E7
+#define REG_AUDIO_BEEP		0xF4D0
+/* USB port power or not: rd/wr */
+#define REG_USB0_FLAG		0xF461
+#define REG_USB1_FLAG		0xF462
+#define REG_USB2_FLAG		0xF463
+#define BIT_USB_FLAG_ON		1
+#define BIT_USB_FLAG_OFF	0
+/* LID */
+#define REG_LID_DETECT		0xF4BD
+#define BIT_LID_DETECT_ON	1
+#define BIT_LID_DETECT_OFF	0
+/* CRT */
+#define REG_CRT_DETECT		0xF4AD
+#define BIT_CRT_DETECT_PLUG	1
+#define BIT_CRT_DETECT_UNPLUG	0
+/* LCD backlight brightness adjust: 9 levels */
+#define REG_DISPLAY_BRIGHTNESS	0xF4F5
+/* Black screen Status */
+#define BIT_DISPLAY_LCD_ON	1
+#define BIT_DISPLAY_LCD_OFF	0
+/* LCD backlight control: off/restore */
+#define REG_BACKLIGHT_CTRL	0xF7BD
+#define BIT_BACKLIGHT_ON	1
+#define BIT_BACKLIGHT_OFF	0
+/* Reset the machine auto-clear: rd/wr */
+#define REG_RESET		0xF4EC
+#define BIT_RESET_ON		1
+/* Light the led: rd/wr */
+#define REG_LED			0xF4C8
+#define BIT_LED_RED_POWER	(1 << 0)
+#define BIT_LED_ORANGE_POWER	(1 << 1)
+#define BIT_LED_GREEN_CHARGE	(1 << 2)
+#define BIT_LED_RED_CHARGE	(1 << 3)
+#define BIT_LED_NUMLOCK		(1 << 4)
+/* Test led mode, all led on/off */
+#define REG_LED_TEST		0xF4C2
+#define BIT_LED_TEST_IN		1
+#define BIT_LED_TEST_OUT	0
+/* Camera on/off */
+#define REG_CAMERA_STATUS	0xF46A
+#define BIT_CAMERA_STATUS_ON	1
+#define BIT_CAMERA_STATUS_OFF	0
+#define REG_CAMERA_CONTROL	0xF7B7
+#define BIT_CAMERA_CONTROL_OFF	0
+#define BIT_CAMERA_CONTROL_ON	1
+/* Wlan Status */
+#define REG_WLAN		0xF4FA
+#define BIT_WLAN_ON		1
+#define BIT_WLAN_OFF		0
+#define REG_DISPLAY_LCD		0xF79F
+
+/* SCI Event Number from EC */
+enum {
+	EVENT_LID = 0x23,	/*  LID open/close */
+	EVENT_DISPLAY_TOGGLE,	/*  Fn+F3 for display switch */
+	EVENT_SLEEP,		/*  Fn+F1 for entering sleep mode */
+	EVENT_OVERTEMP,		/*  Over-temperature happened */
+	EVENT_CRT_DETECT,	/*  CRT is connected */
+	EVENT_CAMERA,		/*  Camera on/off */
+	EVENT_USB_OC2,		/*  USB2 Over Current occurred */
+	EVENT_USB_OC0,		/*  USB0 Over Current occurred */
+	EVENT_BLACK_SCREEN,	/*  Turn on/off backlight */
+	EVENT_AUDIO_MUTE,	/*  Mute on/off */
+	EVENT_DISPLAY_BRIGHTNESS,/* LCD backlight brightness adjust */
+	EVENT_AC_BAT,		/*  AC & Battery relative issue */
+	EVENT_AUDIO_VOLUME,	/*  Volume adjust */
+	EVENT_WLAN,		/*  Wlan on/off */
+	EVENT_END
+};
+
+#endif /* !_EC_KB3310B_H */
diff --git a/arch/mips/loongson2ef/lemote-2f/irq.c b/arch/mips/loongson2ef/lemote-2f/irq.c
new file mode 100644
index 0000000..6f00579
--- /dev/null
+++ b/arch/mips/loongson2ef/lemote-2f/irq.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2007 Lemote Inc.
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ */
+
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/i8259.h>
+#include <asm/mipsregs.h>
+
+#include <loongson.h>
+#include <machine.h>
+
+#define LOONGSON_TIMER_IRQ	(MIPS_CPU_IRQ_BASE + 7) /* cpu timer */
+#define LOONGSON_NORTH_BRIDGE_IRQ	(MIPS_CPU_IRQ_BASE + 6) /* bonito */
+#define LOONGSON_UART_IRQ	(MIPS_CPU_IRQ_BASE + 3) /* cpu serial port */
+#define LOONGSON_SOUTH_BRIDGE_IRQ	(MIPS_CPU_IRQ_BASE + 2) /* i8259 */
+
+#define LOONGSON_INT_BIT_INT0		(1 << 11)
+#define LOONGSON_INT_BIT_INT1		(1 << 12)
+
+/*
+ * The generic i8259_irq() make the kernel hang on booting.  Since we cannot
+ * get the irq via the IRR directly, we access the ISR instead.
+ */
+int mach_i8259_irq(void)
+{
+	int irq, isr;
+
+	irq = -1;
+
+	if ((LOONGSON_INTISR & LOONGSON_INTEN) & LOONGSON_INT_BIT_INT0) {
+		raw_spin_lock(&i8259A_lock);
+		isr = inb(PIC_MASTER_CMD) &
+			~inb(PIC_MASTER_IMR) & ~(1 << PIC_CASCADE_IR);
+		if (!isr)
+			isr = (inb(PIC_SLAVE_CMD) & ~inb(PIC_SLAVE_IMR)) << 8;
+		irq = ffs(isr) - 1;
+		if (unlikely(irq == 7)) {
+			/*
+			 * This may be a spurious interrupt.
+			 *
+			 * Read the interrupt status register (ISR). If the most
+			 * significant bit is not set then there is no valid
+			 * interrupt.
+			 */
+			outb(0x0B, PIC_MASTER_ISR);	/* ISR register */
+			if (~inb(PIC_MASTER_ISR) & 0x80)
+				irq = -1;
+		}
+		raw_spin_unlock(&i8259A_lock);
+	}
+
+	return irq;
+}
+EXPORT_SYMBOL(mach_i8259_irq);
+
+static void i8259_irqdispatch(void)
+{
+	int irq;
+
+	irq = mach_i8259_irq();
+	if (irq >= 0)
+		do_IRQ(irq);
+	else
+		spurious_interrupt();
+}
+
+void mach_irq_dispatch(unsigned int pending)
+{
+	if (pending & CAUSEF_IP7)
+		do_IRQ(LOONGSON_TIMER_IRQ);
+	else if (pending & CAUSEF_IP6) {	/* North Bridge, Perf counter */
+		do_perfcnt_IRQ();
+		bonito_irqdispatch();
+	} else if (pending & CAUSEF_IP3)	/* CPU UART */
+		do_IRQ(LOONGSON_UART_IRQ);
+	else if (pending & CAUSEF_IP2)	/* South Bridge */
+		i8259_irqdispatch();
+	else
+		spurious_interrupt();
+}
+
+static irqreturn_t ip6_action(int cpl, void *dev_id)
+{
+	return IRQ_HANDLED;
+}
+
+void __init mach_init_irq(void)
+{
+	/* init all controller
+	 *   0-15	  ------> i8259 interrupt
+	 *   16-23	  ------> mips cpu interrupt
+	 *   32-63	  ------> bonito irq
+	 */
+
+	/* setup cs5536 as high level trigger */
+	LOONGSON_INTPOL = LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1;
+	LOONGSON_INTEDGE &= ~(LOONGSON_INT_BIT_INT0 | LOONGSON_INT_BIT_INT1);
+
+	/* Sets the first-level interrupt dispatcher. */
+	mips_cpu_irq_init();
+	init_i8259_irqs();
+	bonito_irq_init();
+
+	/* setup north bridge irq (bonito) */
+	if (request_irq(LOONGSON_NORTH_BRIDGE_IRQ, ip6_action,
+			IRQF_SHARED | IRQF_NO_THREAD, "cascade", ip6_action))
+		pr_err("Failed to register north bridge cascade interrupt\n");
+	/* setup source bridge irq (i8259) */
+	if (request_irq(LOONGSON_SOUTH_BRIDGE_IRQ, no_action,
+			IRQF_NO_THREAD | IRQF_NO_SUSPEND, "cascade", NULL))
+		pr_err("Failed to register south bridge cascade interrupt\n");
+}
diff --git a/arch/mips/loongson2ef/lemote-2f/machtype.c b/arch/mips/loongson2ef/lemote-2f/machtype.c
new file mode 100644
index 0000000..9462a3a
--- /dev/null
+++ b/arch/mips/loongson2ef/lemote-2f/machtype.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ */
+#include <asm/bootinfo.h>
+
+#include <loongson.h>
+
+void __init mach_prom_init_machtype(void)
+{
+	/* We share the same kernel image file among Lemote 2F family
+	 * of machines, and provide the machtype= kernel command line
+	 * to users to indicate their machine, this command line will
+	 * be passed by the latest PMON automatically. and fortunately,
+	 * up to now, we can get the machine type from the PMON_VER=
+	 * commandline directly except the NAS machine, In the old
+	 * machines, this will help the users a lot.
+	 *
+	 * If no "machtype=" passed, get machine type from "PMON_VER=".
+	 *	PMON_VER=LM8089		Lemote 8.9'' netbook
+	 *		 LM8101		Lemote 10.1'' netbook
+	 *	(The above two netbooks have the same kernel support)
+	 *		 LM6XXX		Lemote FuLoong(2F) box series
+	 *		 LM9XXX		Lemote LynLoong PC series
+	 */
+	if (strstr(arcs_cmdline, "PMON_VER=LM")) {
+		if (strstr(arcs_cmdline, "PMON_VER=LM8"))
+			mips_machtype = MACH_LEMOTE_YL2F89;
+		else if (strstr(arcs_cmdline, "PMON_VER=LM6"))
+			mips_machtype = MACH_LEMOTE_FL2F;
+		else if (strstr(arcs_cmdline, "PMON_VER=LM9"))
+			mips_machtype = MACH_LEMOTE_LL2F;
+		else
+			mips_machtype = MACH_LEMOTE_NAS;
+
+		strcat(arcs_cmdline, " machtype=");
+		strcat(arcs_cmdline, get_system_type());
+		strcat(arcs_cmdline, " ");
+	}
+}
diff --git a/arch/mips/loongson2ef/lemote-2f/pm.c b/arch/mips/loongson2ef/lemote-2f/pm.c
new file mode 100644
index 0000000..3d00272
--- /dev/null
+++ b/arch/mips/loongson2ef/lemote-2f/pm.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Lemote loongson2f family machines' specific suspend support
+ *
+ *  Copyright (C) 2009 Lemote Inc.
+ *  Author: Wu Zhangjin <wuzhangjin@gmail.com>
+ */
+
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/i8042.h>
+#include <linux/export.h>
+
+#include <asm/i8259.h>
+#include <asm/mipsregs.h>
+#include <asm/bootinfo.h>
+
+#include <loongson.h>
+
+#include <cs5536/cs5536_mfgpt.h>
+#include "ec_kb3310b.h"
+
+#define I8042_KBD_IRQ		1
+#define I8042_CTR_KBDINT	0x01
+#define I8042_CTR_KBDDIS	0x10
+
+static unsigned char i8042_ctr;
+
+static int i8042_enable_kbd_port(void)
+{
+	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) {
+		pr_err("i8042.c: Can't read CTR while enabling i8042 kbd port."
+		       "\n");
+		return -EIO;
+	}
+
+	i8042_ctr &= ~I8042_CTR_KBDDIS;
+	i8042_ctr |= I8042_CTR_KBDINT;
+
+	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+		i8042_ctr &= ~I8042_CTR_KBDINT;
+		i8042_ctr |= I8042_CTR_KBDDIS;
+		pr_err("i8042.c: Failed to enable KBD port.\n");
+
+		return -EIO;
+	}
+
+	return 0;
+}
+
+void setup_wakeup_events(void)
+{
+	int irq_mask;
+
+	switch (mips_machtype) {
+	case MACH_LEMOTE_ML2F7:
+	case MACH_LEMOTE_YL2F89:
+		/* open the keyboard irq in i8259A */
+		outb((0xff & ~(1 << I8042_KBD_IRQ)), PIC_MASTER_IMR);
+		irq_mask = inb(PIC_MASTER_IMR);
+
+		/* enable keyboard port */
+		i8042_enable_kbd_port();
+
+		/* Wakeup CPU via SCI lid open event */
+		outb(irq_mask & ~(1 << PIC_CASCADE_IR), PIC_MASTER_IMR);
+		inb(PIC_MASTER_IMR);
+		outb(0xff & ~(1 << (SCI_IRQ_NUM - 8)), PIC_SLAVE_IMR);
+		inb(PIC_SLAVE_IMR);
+
+		break;
+
+	default:
+		break;
+	}
+}
+
+static struct delayed_work lid_task;
+static int initialized;
+/* yeeloong_report_lid_status will be implemented in yeeloong_laptop.c */
+sci_handler yeeloong_report_lid_status;
+EXPORT_SYMBOL(yeeloong_report_lid_status);
+static void yeeloong_lid_update_task(struct work_struct *work)
+{
+	if (yeeloong_report_lid_status)
+		yeeloong_report_lid_status(BIT_LID_DETECT_ON);
+}
+
+int wakeup_loongson(void)
+{
+	int irq;
+
+	/* query the interrupt number */
+	irq = mach_i8259_irq();
+	if (irq < 0)
+		return 0;
+
+	printk(KERN_INFO "%s: irq = %d\n", __func__, irq);
+
+	if (irq == I8042_KBD_IRQ)
+		return 1;
+	else if (irq == SCI_IRQ_NUM) {
+		int ret, sci_event;
+		/* query the event number */
+		ret = ec_query_seq(CMD_GET_EVENT_NUM);
+		if (ret < 0)
+			return 0;
+		sci_event = ec_get_event_num();
+		if (sci_event < 0)
+			return 0;
+		if (sci_event == EVENT_LID) {
+			int lid_status;
+			/* check the LID status */
+			lid_status = ec_read(REG_LID_DETECT);
+			/* wakeup cpu when people open the LID */
+			if (lid_status == BIT_LID_DETECT_ON) {
+				/* If we call it directly here, the WARNING
+				 * will be sent out by getnstimeofday
+				 * via "WARN_ON(timekeeping_suspended);"
+				 * because we can not schedule in suspend mode.
+				 */
+				if (initialized == 0) {
+					INIT_DELAYED_WORK(&lid_task,
+						yeeloong_lid_update_task);
+					initialized = 1;
+				}
+				schedule_delayed_work(&lid_task, 1);
+				return 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+void __weak mach_suspend(void)
+{
+	disable_mfgpt0_counter();
+}
+
+void __weak mach_resume(void)
+{
+	enable_mfgpt0_counter();
+}
diff --git a/arch/mips/loongson2ef/lemote-2f/reset.c b/arch/mips/loongson2ef/lemote-2f/reset.c
new file mode 100644
index 0000000..197dae4
--- /dev/null
+++ b/arch/mips/loongson2ef/lemote-2f/reset.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Board-specific reboot/shutdown routines
+ *
+ * Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca>
+ *
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+
+#include <asm/bootinfo.h>
+
+#include <loongson.h>
+
+#include <cs5536/cs5536.h>
+#include "ec_kb3310b.h"
+
+static void reset_cpu(void)
+{
+	/*
+	 * reset cpu to full speed, this is needed when enabling cpu frequency
+	 * scalling
+	 */
+	writel(readl(LOONGSON_CHIPCFG) | 0x7, LOONGSON_CHIPCFG);
+}
+
+/* reset support for fuloong2f */
+
+static void fl2f_reboot(void)
+{
+	reset_cpu();
+
+	/* send a reset signal to south bridge.
+	 *
+	 * NOTE: if enable "Power Management" in kernel, rtl8169 will not reset
+	 * normally with this reset operation and it will not work in PMON, but
+	 * you can type halt command and then reboot, seems the hardware reset
+	 * logic not work normally.
+	 */
+	{
+		u32 hi, lo;
+		_rdmsr(DIVIL_MSR_REG(DIVIL_SOFT_RESET), &hi, &lo);
+		lo |= 0x00000001;
+		_wrmsr(DIVIL_MSR_REG(DIVIL_SOFT_RESET), hi, lo);
+	}
+}
+
+static void fl2f_shutdown(void)
+{
+	u32 hi, lo, val;
+	int gpio_base;
+
+	/* get gpio base */
+	_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo);
+	gpio_base = lo & 0xff00;
+
+	/* make cs5536 gpio13 output enable */
+	val = inl(gpio_base + GPIOL_OUT_EN);
+	val &= ~(1 << (16 + 13));
+	val |= (1 << 13);
+	outl(val, gpio_base + GPIOL_OUT_EN);
+	mmiowb();
+	/* make cs5536 gpio13 output low level voltage. */
+	val = inl(gpio_base + GPIOL_OUT_VAL) & ~(1 << (13));
+	val |= (1 << (16 + 13));
+	outl(val, gpio_base + GPIOL_OUT_VAL);
+	mmiowb();
+}
+
+/* reset support for yeeloong2f and mengloong2f notebook */
+
+static void ml2f_reboot(void)
+{
+	reset_cpu();
+
+	/* sending an reset signal to EC(embedded controller) */
+	ec_write(REG_RESET, BIT_RESET_ON);
+}
+
+#define yl2f89_reboot ml2f_reboot
+
+/* menglong(7inches) laptop has different shutdown logic from 8.9inches */
+#define EC_SHUTDOWN_IO_PORT_HIGH 0xff2d
+#define EC_SHUTDOWN_IO_PORT_LOW	 0xff2e
+#define EC_SHUTDOWN_IO_PORT_DATA 0xff2f
+#define REG_SHUTDOWN_HIGH	 0xFC
+#define REG_SHUTDOWN_LOW	 0x29
+#define BIT_SHUTDOWN_ON		 (1 << 1)
+
+static void ml2f_shutdown(void)
+{
+	u8 val;
+	u64 i;
+
+	outb(REG_SHUTDOWN_HIGH, EC_SHUTDOWN_IO_PORT_HIGH);
+	outb(REG_SHUTDOWN_LOW, EC_SHUTDOWN_IO_PORT_LOW);
+	mmiowb();
+	val = inb(EC_SHUTDOWN_IO_PORT_DATA);
+	outb(val & (~BIT_SHUTDOWN_ON), EC_SHUTDOWN_IO_PORT_DATA);
+	mmiowb();
+	/* need enough wait here... how many microseconds needs? */
+	for (i = 0; i < 0x10000; i++)
+		delay();
+	outb(val | BIT_SHUTDOWN_ON, EC_SHUTDOWN_IO_PORT_DATA);
+	mmiowb();
+}
+
+static void yl2f89_shutdown(void)
+{
+	/* cpu-gpio0 output low */
+	LOONGSON_GPIODATA &= ~0x00000001;
+	/* cpu-gpio0 as output */
+	LOONGSON_GPIOIE &= ~0x00000001;
+}
+
+void mach_prepare_reboot(void)
+{
+	switch (mips_machtype) {
+	case MACH_LEMOTE_FL2F:
+	case MACH_LEMOTE_NAS:
+	case MACH_LEMOTE_LL2F:
+		fl2f_reboot();
+		break;
+	case MACH_LEMOTE_ML2F7:
+		ml2f_reboot();
+		break;
+	case MACH_LEMOTE_YL2F89:
+		yl2f89_reboot();
+		break;
+	default:
+		break;
+	}
+}
+
+void mach_prepare_shutdown(void)
+{
+	switch (mips_machtype) {
+	case MACH_LEMOTE_FL2F:
+	case MACH_LEMOTE_NAS:
+	case MACH_LEMOTE_LL2F:
+		fl2f_shutdown();
+		break;
+	case MACH_LEMOTE_ML2F7:
+		ml2f_shutdown();
+		break;
+	case MACH_LEMOTE_YL2F89:
+		yl2f89_shutdown();
+		break;
+	default:
+		break;
+	}
+}