MIPS: Loongson64: Move files to the top-level directory
authorJiaxun Yang <jiaxun.yang@flygoat.com>
Sun, 20 Oct 2019 15:01:36 +0000 (23:01 +0800)
committerPaul Burton <paulburton@kernel.org>
Fri, 1 Nov 2019 21:31:28 +0000 (14:31 -0700)
Current Loongson-3 code can share among all Loongson64 processors.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Paul Burton <paulburton@kernel.org>
Cc: linux-mips@vger.kernel.org
Cc: chenhc@lemote.com
Cc: paul.burton@mips.com
45 files changed:
arch/mips/Kconfig
arch/mips/configs/loongson3_defconfig
arch/mips/include/asm/mach-loongson64/cpu-feature-overrides.h
arch/mips/loongson64/Kconfig
arch/mips/loongson64/Makefile
arch/mips/loongson64/acpi_init.c [new file with mode: 0644]
arch/mips/loongson64/cmdline.c [new file with mode: 0644]
arch/mips/loongson64/common/Makefile [deleted file]
arch/mips/loongson64/common/cmdline.c [deleted file]
arch/mips/loongson64/common/env.c [deleted file]
arch/mips/loongson64/common/init.c [deleted file]
arch/mips/loongson64/common/pci.c [deleted file]
arch/mips/loongson64/common/pm.c [deleted file]
arch/mips/loongson64/common/reset.c [deleted file]
arch/mips/loongson64/common/rtc.c [deleted file]
arch/mips/loongson64/common/setup.c [deleted file]
arch/mips/loongson64/common/time.c [deleted file]
arch/mips/loongson64/cop2-ex.c [new file with mode: 0644]
arch/mips/loongson64/dma.c [new file with mode: 0644]
arch/mips/loongson64/env.c [new file with mode: 0644]
arch/mips/loongson64/hpet.c [new file with mode: 0644]
arch/mips/loongson64/init.c [new file with mode: 0644]
arch/mips/loongson64/irq.c [new file with mode: 0644]
arch/mips/loongson64/loongson-3/Makefile [deleted file]
arch/mips/loongson64/loongson-3/acpi_init.c [deleted file]
arch/mips/loongson64/loongson-3/cop2-ex.c [deleted file]
arch/mips/loongson64/loongson-3/dma.c [deleted file]
arch/mips/loongson64/loongson-3/hpet.c [deleted file]
arch/mips/loongson64/loongson-3/irq.c [deleted file]
arch/mips/loongson64/loongson-3/numa.c [deleted file]
arch/mips/loongson64/loongson-3/platform.c [deleted file]
arch/mips/loongson64/loongson-3/smp.c [deleted file]
arch/mips/loongson64/loongson-3/smp.h [deleted file]
arch/mips/loongson64/numa.c [new file with mode: 0644]
arch/mips/loongson64/pci.c [new file with mode: 0644]
arch/mips/loongson64/platform.c [new file with mode: 0644]
arch/mips/loongson64/pm.c [new file with mode: 0644]
arch/mips/loongson64/reset.c [new file with mode: 0644]
arch/mips/loongson64/rtc.c [new file with mode: 0644]
arch/mips/loongson64/setup.c [new file with mode: 0644]
arch/mips/loongson64/smp.c [new file with mode: 0644]
arch/mips/loongson64/smp.h [new file with mode: 0644]
arch/mips/loongson64/time.c [new file with mode: 0644]
arch/mips/pci/Makefile
drivers/platform/mips/Kconfig

index aa6f8497ddd9c035dca5c016290dbf2e7c8feae5..b303b5c2d764a1432f0c4ccfbfa7ce6543d8a517 100644 (file)
@@ -461,7 +461,33 @@ config MACH_LOONGSON2EF
 
 config MACH_LOONGSON64
        bool "Loongson-2/3 GSx64 family of machines"
+       select ARCH_SPARSEMEM_ENABLE
+       select ARCH_MIGHT_HAVE_PC_PARPORT
+       select ARCH_MIGHT_HAVE_PC_SERIO
+       select GENERIC_ISA_DMA_SUPPORT_BROKEN
+       select BOOT_ELF32
+       select BOARD_SCACHE
+       select CSRC_R4K
+       select CEVT_R4K
+       select CPU_HAS_WB
+       select FORCE_PCI
+       select ISA
+       select I8259
+       select IRQ_MIPS_CPU
+       select NR_CPUS_DEFAULT_4
+       select USE_GENERIC_EARLY_PRINTK_8250
+       select SYS_HAS_CPU_LOONGSON64
+       select SYS_HAS_EARLY_PRINTK
+       select SYS_SUPPORTS_SMP
+       select SYS_SUPPORTS_HOTPLUG_CPU
+       select SYS_SUPPORTS_NUMA
+       select SYS_SUPPORTS_64BIT_KERNEL
+       select SYS_SUPPORTS_HIGHMEM
+       select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_SUPPORTS_ZBOOT
+       select LOONGSON_MC146818
+       select ZONE_DMA32
+       select NUMA
        help
          This enables the support of Loongson-2/3 family of processors with
          GSx64 microarchitecture.
index 90ee0084d7862a7c260ac6b9db572bf7a0e437ed..caad7bf7902caa76f2804b1c79ca8613cc8dae0b 100644 (file)
@@ -24,7 +24,6 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_SYSCTL_SYSCALL=y
 CONFIG_EMBEDDED=y
 CONFIG_MACH_LOONGSON64=y
-CONFIG_LOONGSON_MACH3X=y
 CONFIG_SMP=y
 CONFIG_HZ_256=y
 CONFIG_KEXEC=y
index 895607eb81ca6f4be5101cf3146a5aa859a7c98d..7dc8d75445a961e2055af39f2b765d73af5f663c 100644 (file)
@@ -43,7 +43,6 @@
 #define cpu_has_vint           0
 #define cpu_has_vtag_icache    0
 #define cpu_has_watch          1
-
 #define cpu_has_wsbh           1
 #define cpu_has_ic_fills_f_dc  1
 #define cpu_hwrena_impl_bits   0xc0000000
index 3215b768bb88058cbd7e3318dd6fb2abb062746f..b1aefd06e3f5eb0911ec23ef3d8c41c802a40836 100644 (file)
@@ -1,45 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0
 if MACH_LOONGSON64
 
-choice
-       prompt "Machine Type"
-
-config LOONGSON_MACH3X
-       bool "Generic Loongson 3 family machines"
-       select ARCH_SPARSEMEM_ENABLE
-       select ARCH_MIGHT_HAVE_PC_PARPORT
-       select ARCH_MIGHT_HAVE_PC_SERIO
-       select GENERIC_ISA_DMA_SUPPORT_BROKEN
-       select BOOT_ELF32
-       select BOARD_SCACHE
-       select CSRC_R4K
-       select CEVT_R4K
-       select CPU_HAS_WB
-       select FORCE_PCI
-       select ISA
-       select I8259
-       select IRQ_MIPS_CPU
-       select NR_CPUS_DEFAULT_4
-       select USE_GENERIC_EARLY_PRINTK_8250
-       select SYS_HAS_CPU_LOONGSON64
-       select SYS_HAS_EARLY_PRINTK
-       select SYS_SUPPORTS_SMP
-       select SYS_SUPPORTS_HOTPLUG_CPU
-       select SYS_SUPPORTS_NUMA
-       select SYS_SUPPORTS_64BIT_KERNEL
-       select SYS_SUPPORTS_HIGHMEM
-       select SYS_SUPPORTS_LITTLE_ENDIAN
-       select LOONGSON_MC146818
-       select ZONE_DMA32
-       select NUMA
-       help
-               Generic Loongson 3 family machines utilize the 3A/3B revision
-               of Loongson processor and RS780/SBX00 chipset.
-endchoice
-
 config RS780_HPET
        bool "RS780/SBX00 HPET Timer"
-       depends on LOONGSON_MACH3X
+       depends on CONFIG_MACH_LOONGSON64
        select MIPS_EXTERNAL_TIMER
        help
          This option enables the hpet timer of AMD RS780/SBX00.
index dc16a23c171ffe8a46733fb539208697d084e1aa..0b3c65b52965ebc82a0dc643f07654d86735f492 100644 (file)
@@ -1,12 +1,13 @@
 # SPDX-License-Identifier: GPL-2.0-only
 #
-# Common code for all Loongson based systems
+# Makefile for Loongson-3 family machines
 #
+obj-$(CONFIG_MACH_LOONGSON64) += irq.o cop2-ex.o platform.o acpi_init.o dma.o \
+                               setup.o init.o cmdline.o env.o time.o reset.o \
 
-obj-$(CONFIG_MACH_LOONGSON64) += common/
-
-#
-# All Loongson-3 family machines
-#
-
-obj-$(CONFIG_CPU_LOONGSON64)  += loongson-3/
+obj-$(CONFIG_SMP)      += smp.o
+obj-$(CONFIG_NUMA)     += numa.o
+obj-$(CONFIG_RS780_HPET) += hpet.o
+obj-$(CONFIG_PCI) += pci.o
+obj-$(CONFIG_LOONGSON_MC146818) += rtc.o
+obj-$(CONFIG_SUSPEND) += pm.o
diff --git a/arch/mips/loongson64/acpi_init.c b/arch/mips/loongson64/acpi_init.c
new file mode 100644 (file)
index 0000000..8d7c119
--- /dev/null
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/export.h>
+
+#define SBX00_ACPI_IO_BASE 0x800
+#define SBX00_ACPI_IO_SIZE 0x100
+
+#define ACPI_PM_EVT_BLK         (SBX00_ACPI_IO_BASE + 0x00) /* 4 bytes */
+#define ACPI_PM_CNT_BLK         (SBX00_ACPI_IO_BASE + 0x04) /* 2 bytes */
+#define ACPI_PMA_CNT_BLK        (SBX00_ACPI_IO_BASE + 0x0F) /* 1 byte */
+#define ACPI_PM_TMR_BLK         (SBX00_ACPI_IO_BASE + 0x18) /* 4 bytes */
+#define ACPI_GPE0_BLK           (SBX00_ACPI_IO_BASE + 0x10) /* 8 bytes */
+#define ACPI_END                (SBX00_ACPI_IO_BASE + 0x80)
+
+#define PM_INDEX        0xCD6
+#define PM_DATA         0xCD7
+#define PM2_INDEX       0xCD0
+#define PM2_DATA        0xCD1
+
+/*
+ * SCI interrupt need acpi space, allocate here
+ */
+
+static int __init register_acpi_resource(void)
+{
+       request_region(SBX00_ACPI_IO_BASE, SBX00_ACPI_IO_SIZE, "acpi");
+       return 0;
+}
+
+static void pmio_write_index(u16 index, u8 reg, u8 value)
+{
+       outb(reg, index);
+       outb(value, index + 1);
+}
+
+static u8 pmio_read_index(u16 index, u8 reg)
+{
+       outb(reg, index);
+       return inb(index + 1);
+}
+
+void pm_iowrite(u8 reg, u8 value)
+{
+       pmio_write_index(PM_INDEX, reg, value);
+}
+EXPORT_SYMBOL(pm_iowrite);
+
+u8 pm_ioread(u8 reg)
+{
+       return pmio_read_index(PM_INDEX, reg);
+}
+EXPORT_SYMBOL(pm_ioread);
+
+void pm2_iowrite(u8 reg, u8 value)
+{
+       pmio_write_index(PM2_INDEX, reg, value);
+}
+EXPORT_SYMBOL(pm2_iowrite);
+
+u8 pm2_ioread(u8 reg)
+{
+       return pmio_read_index(PM2_INDEX, reg);
+}
+EXPORT_SYMBOL(pm2_ioread);
+
+static void acpi_hw_clear_status(void)
+{
+       u16 value;
+
+       /* PMStatus: Clear WakeStatus/PwrBtnStatus */
+       value = inw(ACPI_PM_EVT_BLK);
+       value |= (1 << 8 | 1 << 15);
+       outw(value, ACPI_PM_EVT_BLK);
+
+       /* GPEStatus: Clear all generated events */
+       outl(inl(ACPI_GPE0_BLK), ACPI_GPE0_BLK);
+}
+
+void acpi_registers_setup(void)
+{
+       u32 value;
+
+       /* PM Status Base */
+       pm_iowrite(0x20, ACPI_PM_EVT_BLK & 0xff);
+       pm_iowrite(0x21, ACPI_PM_EVT_BLK >> 8);
+
+       /* PM Control Base */
+       pm_iowrite(0x22, ACPI_PM_CNT_BLK & 0xff);
+       pm_iowrite(0x23, ACPI_PM_CNT_BLK >> 8);
+
+       /* GPM Base */
+       pm_iowrite(0x28, ACPI_GPE0_BLK & 0xff);
+       pm_iowrite(0x29, ACPI_GPE0_BLK >> 8);
+
+       /* ACPI End */
+       pm_iowrite(0x2e, ACPI_END & 0xff);
+       pm_iowrite(0x2f, ACPI_END >> 8);
+
+       /* IO Decode: When AcpiDecodeEnable set, South-Bridge uses the contents
+        * of the PM registers at index 0x20~0x2B to decode ACPI I/O address. */
+       pm_iowrite(0x0e, 1 << 3);
+
+       /* SCI_EN set */
+       outw(1, ACPI_PM_CNT_BLK);
+
+       /* Enable to generate SCI */
+       pm_iowrite(0x10, pm_ioread(0x10) | 1);
+
+       /* GPM3/GPM9 enable */
+       value = inl(ACPI_GPE0_BLK + 4);
+       outl(value | (1 << 14) | (1 << 22), ACPI_GPE0_BLK + 4);
+
+       /* Set GPM9 as input */
+       pm_iowrite(0x8d, pm_ioread(0x8d) & (~(1 << 1)));
+
+       /* Set GPM9 as non-output */
+       pm_iowrite(0x94, pm_ioread(0x94) | (1 << 3));
+
+       /* GPM3 config ACPI trigger SCIOUT */
+       pm_iowrite(0x33, pm_ioread(0x33) & (~(3 << 4)));
+
+       /* GPM9 config ACPI trigger SCIOUT */
+       pm_iowrite(0x3d, pm_ioread(0x3d) & (~(3 << 2)));
+
+       /* GPM3 config falling edge trigger */
+       pm_iowrite(0x37, pm_ioread(0x37) & (~(1 << 6)));
+
+       /* No wait for STPGNT# in ACPI Sx state */
+       pm_iowrite(0x7c, pm_ioread(0x7c) | (1 << 6));
+
+       /* Set GPM3 pull-down enable */
+       value = pm2_ioread(0xf6);
+       value |= ((1 << 7) | (1 << 3));
+       pm2_iowrite(0xf6, value);
+
+       /* Set GPM9 pull-down enable */
+       value = pm2_ioread(0xf8);
+       value |= ((1 << 5) | (1 << 1));
+       pm2_iowrite(0xf8, value);
+}
+
+int __init sbx00_acpi_init(void)
+{
+       register_acpi_resource();
+       acpi_registers_setup();
+       acpi_hw_clear_status();
+
+       return 0;
+}
diff --git a/arch/mips/loongson64/cmdline.c b/arch/mips/loongson64/cmdline.c
new file mode 100644 (file)
index 0000000..fb1644b
--- /dev/null
@@ -0,0 +1,42 @@
+// 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 <asm/bootinfo.h>
+
+#include <loongson.h>
+
+void __init prom_init_cmdline(void)
+{
+       int prom_argc;
+       /* pmon passes arguments in 32bit pointers */
+       int *_prom_argv;
+       int i;
+       long l;
+
+       /* firmware arguments are initialized in head.S */
+       prom_argc = fw_arg0;
+       _prom_argv = (int *)fw_arg1;
+
+       /* arg[0] is "g", the rest is boot parameters */
+       arcs_cmdline[0] = '\0';
+       for (i = 1; i < prom_argc; i++) {
+               l = (long)_prom_argv[i];
+               if (strlen(arcs_cmdline) + strlen(((char *)l) + 1)
+                   >= sizeof(arcs_cmdline))
+                       break;
+               strcat(arcs_cmdline, ((char *)l));
+               strcat(arcs_cmdline, " ");
+       }
+}
diff --git a/arch/mips/loongson64/common/Makefile b/arch/mips/loongson64/common/Makefile
deleted file mode 100644 (file)
index c476401..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Makefile for loongson based machines.
-#
-
-obj-y += setup.o init.o cmdline.o env.o time.o reset.o
-
-obj-$(CONFIG_PCI) += pci.o
-
-obj-$(CONFIG_LOONGSON_MC146818) += rtc.o
-
-#
-# Suspend Support
-#
-
-obj-$(CONFIG_SUSPEND) += pm.o
diff --git a/arch/mips/loongson64/common/cmdline.c b/arch/mips/loongson64/common/cmdline.c
deleted file mode 100644 (file)
index fb1644b..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-// 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 <asm/bootinfo.h>
-
-#include <loongson.h>
-
-void __init prom_init_cmdline(void)
-{
-       int prom_argc;
-       /* pmon passes arguments in 32bit pointers */
-       int *_prom_argv;
-       int i;
-       long l;
-
-       /* firmware arguments are initialized in head.S */
-       prom_argc = fw_arg0;
-       _prom_argv = (int *)fw_arg1;
-
-       /* arg[0] is "g", the rest is boot parameters */
-       arcs_cmdline[0] = '\0';
-       for (i = 1; i < prom_argc; i++) {
-               l = (long)_prom_argv[i];
-               if (strlen(arcs_cmdline) + strlen(((char *)l) + 1)
-                   >= sizeof(arcs_cmdline))
-                       break;
-               strcat(arcs_cmdline, ((char *)l));
-               strcat(arcs_cmdline, " ");
-       }
-}
diff --git a/arch/mips/loongson64/common/env.c b/arch/mips/loongson64/common/env.c
deleted file mode 100644 (file)
index 0daeb7b..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-// 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 <loongson.h>
-#include <boot_param.h>
-#include <workarounds.h>
-
-u32 cpu_clock_freq;
-EXPORT_SYMBOL(cpu_clock_freq);
-struct efi_memory_map_loongson *loongson_memmap;
-struct loongson_system_configuration loongson_sysconf;
-
-u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180};
-u64 loongson_chiptemp[MAX_PACKAGES];
-u64 loongson_freqctrl[MAX_PACKAGES];
-
-unsigned long long smp_group[4];
-
-const char *get_system_type(void)
-{
-       return "Generic Loongson64 System";
-}
-
-void __init prom_init_env(void)
-{
-       struct boot_params *boot_p;
-       struct loongson_params *loongson_p;
-       struct system_loongson *esys;
-       struct efi_cpuinfo_loongson *ecpu;
-       struct irq_source_routing_table *eirq_source;
-
-       /* firmware arguments are initialized in head.S */
-       boot_p = (struct boot_params *)fw_arg2;
-       loongson_p = &(boot_p->efi.smbios.lp);
-
-       esys = (struct system_loongson *)
-               ((u64)loongson_p + loongson_p->system_offset);
-       ecpu = (struct efi_cpuinfo_loongson *)
-               ((u64)loongson_p + loongson_p->cpu_offset);
-       eirq_source = (struct irq_source_routing_table *)
-               ((u64)loongson_p + loongson_p->irq_offset);
-       loongson_memmap = (struct efi_memory_map_loongson *)
-               ((u64)loongson_p + loongson_p->memory_offset);
-
-       cpu_clock_freq = ecpu->cpu_clock_freq;
-       loongson_sysconf.cputype = ecpu->cputype;
-       switch (ecpu->cputype) {
-       case Legacy_3A:
-       case Loongson_3A:
-               loongson_sysconf.cores_per_node = 4;
-               loongson_sysconf.cores_per_package = 4;
-               smp_group[0] = 0x900000003ff01000;
-               smp_group[1] = 0x900010003ff01000;
-               smp_group[2] = 0x900020003ff01000;
-               smp_group[3] = 0x900030003ff01000;
-               loongson_chipcfg[0] = 0x900000001fe00180;
-               loongson_chipcfg[1] = 0x900010001fe00180;
-               loongson_chipcfg[2] = 0x900020001fe00180;
-               loongson_chipcfg[3] = 0x900030001fe00180;
-               loongson_chiptemp[0] = 0x900000001fe0019c;
-               loongson_chiptemp[1] = 0x900010001fe0019c;
-               loongson_chiptemp[2] = 0x900020001fe0019c;
-               loongson_chiptemp[3] = 0x900030001fe0019c;
-               loongson_freqctrl[0] = 0x900000001fe001d0;
-               loongson_freqctrl[1] = 0x900010001fe001d0;
-               loongson_freqctrl[2] = 0x900020001fe001d0;
-               loongson_freqctrl[3] = 0x900030001fe001d0;
-               loongson_sysconf.ht_control_base = 0x90000EFDFB000000;
-               loongson_sysconf.workarounds = WORKAROUND_CPUFREQ;
-               break;
-       case Legacy_3B:
-       case Loongson_3B:
-               loongson_sysconf.cores_per_node = 4; /* One chip has 2 nodes */
-               loongson_sysconf.cores_per_package = 8;
-               smp_group[0] = 0x900000003ff01000;
-               smp_group[1] = 0x900010003ff05000;
-               smp_group[2] = 0x900020003ff09000;
-               smp_group[3] = 0x900030003ff0d000;
-               loongson_chipcfg[0] = 0x900000001fe00180;
-               loongson_chipcfg[1] = 0x900020001fe00180;
-               loongson_chipcfg[2] = 0x900040001fe00180;
-               loongson_chipcfg[3] = 0x900060001fe00180;
-               loongson_chiptemp[0] = 0x900000001fe0019c;
-               loongson_chiptemp[1] = 0x900020001fe0019c;
-               loongson_chiptemp[2] = 0x900040001fe0019c;
-               loongson_chiptemp[3] = 0x900060001fe0019c;
-               loongson_freqctrl[0] = 0x900000001fe001d0;
-               loongson_freqctrl[1] = 0x900020001fe001d0;
-               loongson_freqctrl[2] = 0x900040001fe001d0;
-               loongson_freqctrl[3] = 0x900060001fe001d0;
-               loongson_sysconf.ht_control_base = 0x90001EFDFB000000;
-               loongson_sysconf.workarounds = WORKAROUND_CPUHOTPLUG;
-               break;
-       default:
-               loongson_sysconf.cores_per_node = 1;
-               loongson_sysconf.cores_per_package = 1;
-               loongson_chipcfg[0] = 0x900000001fe00180;
-       }
-
-       loongson_sysconf.nr_cpus = ecpu->nr_cpus;
-       loongson_sysconf.boot_cpu_id = ecpu->cpu_startup_core_id;
-       loongson_sysconf.reserved_cpus_mask = ecpu->reserved_cores_mask;
-       if (ecpu->nr_cpus > NR_CPUS || ecpu->nr_cpus == 0)
-               loongson_sysconf.nr_cpus = NR_CPUS;
-       loongson_sysconf.nr_nodes = (loongson_sysconf.nr_cpus +
-               loongson_sysconf.cores_per_node - 1) /
-               loongson_sysconf.cores_per_node;
-
-       loongson_sysconf.pci_mem_start_addr = eirq_source->pci_mem_start_addr;
-       loongson_sysconf.pci_mem_end_addr = eirq_source->pci_mem_end_addr;
-       loongson_sysconf.pci_io_base = eirq_source->pci_io_start_addr;
-       loongson_sysconf.dma_mask_bits = eirq_source->dma_mask_bits;
-       if (loongson_sysconf.dma_mask_bits < 32 ||
-               loongson_sysconf.dma_mask_bits > 64)
-               loongson_sysconf.dma_mask_bits = 32;
-
-       loongson_sysconf.restart_addr = boot_p->reset_system.ResetWarm;
-       loongson_sysconf.poweroff_addr = boot_p->reset_system.Shutdown;
-       loongson_sysconf.suspend_addr = boot_p->reset_system.DoSuspend;
-
-       loongson_sysconf.vgabios_addr = boot_p->efi.smbios.vga_bios;
-       pr_debug("Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: %llx\n",
-               loongson_sysconf.poweroff_addr, loongson_sysconf.restart_addr,
-               loongson_sysconf.vgabios_addr);
-
-       memset(loongson_sysconf.ecname, 0, 32);
-       if (esys->has_ec)
-               memcpy(loongson_sysconf.ecname, esys->ec_name, 32);
-       loongson_sysconf.workarounds |= esys->workarounds;
-
-       loongson_sysconf.nr_uarts = esys->nr_uarts;
-       if (esys->nr_uarts < 1 || esys->nr_uarts > MAX_UARTS)
-               loongson_sysconf.nr_uarts = 1;
-       memcpy(loongson_sysconf.uarts, esys->uarts,
-               sizeof(struct uart_device) * loongson_sysconf.nr_uarts);
-
-       loongson_sysconf.nr_sensors = esys->nr_sensors;
-       if (loongson_sysconf.nr_sensors > MAX_SENSORS)
-               loongson_sysconf.nr_sensors = 0;
-       if (loongson_sysconf.nr_sensors)
-               memcpy(loongson_sysconf.sensors, esys->sensors,
-                       sizeof(struct sensor_device) * loongson_sysconf.nr_sensors);
-       pr_info("CpuClock = %u\n", cpu_clock_freq);
-}
diff --git a/arch/mips/loongson64/common/init.c b/arch/mips/loongson64/common/init.c
deleted file mode 100644 (file)
index 48b44f4..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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 <loongson.h>
-
-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)
-{
-       prom_init_cmdline();
-       prom_init_env();
-
-       /* init base address of io space */
-       set_io_port_base((unsigned long)
-               ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE));
-
-       prom_init_numa_memory();
-
-       /* Hardcode to CPU UART 0 */
-       setup_8250_early_printk_port(TO_UNCAC(LOONGSON_REG_BASE + 0x1e0), 0, 1024);
-
-       register_smp_ops(&loongson3_smp_ops);
-       board_nmi_handler_setup = mips_nmi_setup;
-}
-
-void __init prom_free_prom_memory(void)
-{
-}
diff --git a/arch/mips/loongson64/common/pci.c b/arch/mips/loongson64/common/pci.c
deleted file mode 100644 (file)
index 7bbe238..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-// 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>
-#include <boot_param.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;
-       loongson_pci_mem_resource.start = loongson_sysconf.pci_mem_start_addr;
-       loongson_pci_mem_resource.end = loongson_sysconf.pci_mem_end_addr;
-
-       register_pci_controller(&loongson_pci_controller);
-
-       sbx00_acpi_init();
-
-       return 0;
-}
-
-arch_initcall(pcibios_init);
diff --git a/arch/mips/loongson64/common/pm.c b/arch/mips/loongson64/common/pm.c
deleted file mode 100644 (file)
index 7c8556f..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-// 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)
-{
-}
-
-void __weak mach_suspend(void)
-{
-}
-
-void __weak mach_resume(void)
-{
-}
-
-static int loongson_pm_enter(suspend_state_t state)
-{
-       mach_suspend();
-
-       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/loongson64/common/reset.c b/arch/mips/loongson64/common/reset.c
deleted file mode 100644 (file)
index 88b3bd5..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-// 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>
-#include <boot_param.h>
-
-static inline void loongson_reboot(void)
-{
-       ((void (*)(void))ioremap_nocache(LOONGSON_BOOT_BASE, 4)) ();
-}
-
-static void loongson_restart(char *command)
-{
-
-       void (*fw_restart)(void) = (void *)loongson_sysconf.restart_addr;
-
-       fw_restart();
-       while (1) {
-               if (cpu_wait)
-                       cpu_wait();
-       }
-}
-
-static void loongson_poweroff(void)
-{
-       void (*fw_poweroff)(void) = (void *)loongson_sysconf.poweroff_addr;
-
-       fw_poweroff();
-       while (1) {
-               if (cpu_wait)
-                       cpu_wait();
-       }
-}
-
-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/loongson64/common/rtc.c b/arch/mips/loongson64/common/rtc.c
deleted file mode 100644 (file)
index 8d7628c..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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/loongson64/common/setup.c b/arch/mips/loongson64/common/setup.c
deleted file mode 100644 (file)
index 4fd27f4..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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/loongson64/common/time.c b/arch/mips/loongson64/common/time.c
deleted file mode 100644 (file)
index 1245f22..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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>
-
-void __init plat_time_init(void)
-{
-       /* setup mips r4k timer */
-       mips_hpt_frequency = cpu_clock_freq / 2;
-
-#ifdef CONFIG_RS780_HPET
-       setup_hpet_timer();
-#endif
-}
-
-void read_persistent_clock64(struct timespec64 *ts)
-{
-       ts->tv_sec = mc146818_get_cmos_time();
-       ts->tv_nsec = 0;
-}
diff --git a/arch/mips/loongson64/cop2-ex.c b/arch/mips/loongson64/cop2-ex.c
new file mode 100644 (file)
index 0000000..9efdfe4
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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) 2014 Lemote Corporation.
+ *   written by Huacai Chen <chenhc@lemote.com>
+ *
+ * based on arch/mips/cavium-octeon/cpu.c
+ * Copyright (C) 2009 Wind River Systems,
+ *   written by Ralf Baechle <ralf@linux-mips.org>
+ */
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/notifier.h>
+#include <linux/ptrace.h>
+
+#include <asm/fpu.h>
+#include <asm/cop2.h>
+#include <asm/current.h>
+#include <asm/mipsregs.h>
+
+static int loongson_cu2_call(struct notifier_block *nfb, unsigned long action,
+       void *data)
+{
+       int fpu_owned;
+       int fr = !test_thread_flag(TIF_32BIT_FPREGS);
+
+       switch (action) {
+       case CU2_EXCEPTION:
+               preempt_disable();
+               fpu_owned = __is_fpu_owner();
+               if (!fr)
+                       set_c0_status(ST0_CU1 | ST0_CU2);
+               else
+                       set_c0_status(ST0_CU1 | ST0_CU2 | ST0_FR);
+               enable_fpu_hazard();
+               KSTK_STATUS(current) |= (ST0_CU1 | ST0_CU2);
+               if (fr)
+                       KSTK_STATUS(current) |= ST0_FR;
+               else
+                       KSTK_STATUS(current) &= ~ST0_FR;
+               /* If FPU is owned, we needn't init or restore fp */
+               if (!fpu_owned) {
+                       set_thread_flag(TIF_USEDFPU);
+                       init_fp_ctx(current);
+                       _restore_fp(current);
+               }
+               preempt_enable();
+
+               return NOTIFY_STOP;     /* Don't call default notifier */
+       }
+
+       return NOTIFY_OK;               /* Let default notifier send signals */
+}
+
+static int __init loongson_cu2_setup(void)
+{
+       return cu2_notifier(loongson_cu2_call, 0);
+}
+early_initcall(loongson_cu2_setup);
diff --git a/arch/mips/loongson64/dma.c b/arch/mips/loongson64/dma.c
new file mode 100644 (file)
index 0000000..5e86635
--- /dev/null
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/dma-direct.h>
+#include <linux/init.h>
+#include <linux/swiotlb.h>
+
+dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+       /* We extract 2bit node id (bit 44~47, only bit 44~45 used now) from
+        * Loongson-3's 48bit address space and embed it into 40bit */
+       long nid = (paddr >> 44) & 0x3;
+       return ((nid << 44) ^ paddr) | (nid << 37);
+}
+
+phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr)
+{
+       /* We extract 2bit node id (bit 44~47, only bit 44~45 used now) from
+        * Loongson-3's 48bit address space and embed it into 40bit */
+       long nid = (daddr >> 37) & 0x3;
+       return ((nid << 37) ^ daddr) | (nid << 44);
+}
+
+void __init plat_swiotlb_setup(void)
+{
+       swiotlb_init(1);
+}
diff --git a/arch/mips/loongson64/env.c b/arch/mips/loongson64/env.c
new file mode 100644 (file)
index 0000000..0daeb7b
--- /dev/null
@@ -0,0 +1,158 @@
+// 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 <loongson.h>
+#include <boot_param.h>
+#include <workarounds.h>
+
+u32 cpu_clock_freq;
+EXPORT_SYMBOL(cpu_clock_freq);
+struct efi_memory_map_loongson *loongson_memmap;
+struct loongson_system_configuration loongson_sysconf;
+
+u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180};
+u64 loongson_chiptemp[MAX_PACKAGES];
+u64 loongson_freqctrl[MAX_PACKAGES];
+
+unsigned long long smp_group[4];
+
+const char *get_system_type(void)
+{
+       return "Generic Loongson64 System";
+}
+
+void __init prom_init_env(void)
+{
+       struct boot_params *boot_p;
+       struct loongson_params *loongson_p;
+       struct system_loongson *esys;
+       struct efi_cpuinfo_loongson *ecpu;
+       struct irq_source_routing_table *eirq_source;
+
+       /* firmware arguments are initialized in head.S */
+       boot_p = (struct boot_params *)fw_arg2;
+       loongson_p = &(boot_p->efi.smbios.lp);
+
+       esys = (struct system_loongson *)
+               ((u64)loongson_p + loongson_p->system_offset);
+       ecpu = (struct efi_cpuinfo_loongson *)
+               ((u64)loongson_p + loongson_p->cpu_offset);
+       eirq_source = (struct irq_source_routing_table *)
+               ((u64)loongson_p + loongson_p->irq_offset);
+       loongson_memmap = (struct efi_memory_map_loongson *)
+               ((u64)loongson_p + loongson_p->memory_offset);
+
+       cpu_clock_freq = ecpu->cpu_clock_freq;
+       loongson_sysconf.cputype = ecpu->cputype;
+       switch (ecpu->cputype) {
+       case Legacy_3A:
+       case Loongson_3A:
+               loongson_sysconf.cores_per_node = 4;
+               loongson_sysconf.cores_per_package = 4;
+               smp_group[0] = 0x900000003ff01000;
+               smp_group[1] = 0x900010003ff01000;
+               smp_group[2] = 0x900020003ff01000;
+               smp_group[3] = 0x900030003ff01000;
+               loongson_chipcfg[0] = 0x900000001fe00180;
+               loongson_chipcfg[1] = 0x900010001fe00180;
+               loongson_chipcfg[2] = 0x900020001fe00180;
+               loongson_chipcfg[3] = 0x900030001fe00180;
+               loongson_chiptemp[0] = 0x900000001fe0019c;
+               loongson_chiptemp[1] = 0x900010001fe0019c;
+               loongson_chiptemp[2] = 0x900020001fe0019c;
+               loongson_chiptemp[3] = 0x900030001fe0019c;
+               loongson_freqctrl[0] = 0x900000001fe001d0;
+               loongson_freqctrl[1] = 0x900010001fe001d0;
+               loongson_freqctrl[2] = 0x900020001fe001d0;
+               loongson_freqctrl[3] = 0x900030001fe001d0;
+               loongson_sysconf.ht_control_base = 0x90000EFDFB000000;
+               loongson_sysconf.workarounds = WORKAROUND_CPUFREQ;
+               break;
+       case Legacy_3B:
+       case Loongson_3B:
+               loongson_sysconf.cores_per_node = 4; /* One chip has 2 nodes */
+               loongson_sysconf.cores_per_package = 8;
+               smp_group[0] = 0x900000003ff01000;
+               smp_group[1] = 0x900010003ff05000;
+               smp_group[2] = 0x900020003ff09000;
+               smp_group[3] = 0x900030003ff0d000;
+               loongson_chipcfg[0] = 0x900000001fe00180;
+               loongson_chipcfg[1] = 0x900020001fe00180;
+               loongson_chipcfg[2] = 0x900040001fe00180;
+               loongson_chipcfg[3] = 0x900060001fe00180;
+               loongson_chiptemp[0] = 0x900000001fe0019c;
+               loongson_chiptemp[1] = 0x900020001fe0019c;
+               loongson_chiptemp[2] = 0x900040001fe0019c;
+               loongson_chiptemp[3] = 0x900060001fe0019c;
+               loongson_freqctrl[0] = 0x900000001fe001d0;
+               loongson_freqctrl[1] = 0x900020001fe001d0;
+               loongson_freqctrl[2] = 0x900040001fe001d0;
+               loongson_freqctrl[3] = 0x900060001fe001d0;
+               loongson_sysconf.ht_control_base = 0x90001EFDFB000000;
+               loongson_sysconf.workarounds = WORKAROUND_CPUHOTPLUG;
+               break;
+       default:
+               loongson_sysconf.cores_per_node = 1;
+               loongson_sysconf.cores_per_package = 1;
+               loongson_chipcfg[0] = 0x900000001fe00180;
+       }
+
+       loongson_sysconf.nr_cpus = ecpu->nr_cpus;
+       loongson_sysconf.boot_cpu_id = ecpu->cpu_startup_core_id;
+       loongson_sysconf.reserved_cpus_mask = ecpu->reserved_cores_mask;
+       if (ecpu->nr_cpus > NR_CPUS || ecpu->nr_cpus == 0)
+               loongson_sysconf.nr_cpus = NR_CPUS;
+       loongson_sysconf.nr_nodes = (loongson_sysconf.nr_cpus +
+               loongson_sysconf.cores_per_node - 1) /
+               loongson_sysconf.cores_per_node;
+
+       loongson_sysconf.pci_mem_start_addr = eirq_source->pci_mem_start_addr;
+       loongson_sysconf.pci_mem_end_addr = eirq_source->pci_mem_end_addr;
+       loongson_sysconf.pci_io_base = eirq_source->pci_io_start_addr;
+       loongson_sysconf.dma_mask_bits = eirq_source->dma_mask_bits;
+       if (loongson_sysconf.dma_mask_bits < 32 ||
+               loongson_sysconf.dma_mask_bits > 64)
+               loongson_sysconf.dma_mask_bits = 32;
+
+       loongson_sysconf.restart_addr = boot_p->reset_system.ResetWarm;
+       loongson_sysconf.poweroff_addr = boot_p->reset_system.Shutdown;
+       loongson_sysconf.suspend_addr = boot_p->reset_system.DoSuspend;
+
+       loongson_sysconf.vgabios_addr = boot_p->efi.smbios.vga_bios;
+       pr_debug("Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: %llx\n",
+               loongson_sysconf.poweroff_addr, loongson_sysconf.restart_addr,
+               loongson_sysconf.vgabios_addr);
+
+       memset(loongson_sysconf.ecname, 0, 32);
+       if (esys->has_ec)
+               memcpy(loongson_sysconf.ecname, esys->ec_name, 32);
+       loongson_sysconf.workarounds |= esys->workarounds;
+
+       loongson_sysconf.nr_uarts = esys->nr_uarts;
+       if (esys->nr_uarts < 1 || esys->nr_uarts > MAX_UARTS)
+               loongson_sysconf.nr_uarts = 1;
+       memcpy(loongson_sysconf.uarts, esys->uarts,
+               sizeof(struct uart_device) * loongson_sysconf.nr_uarts);
+
+       loongson_sysconf.nr_sensors = esys->nr_sensors;
+       if (loongson_sysconf.nr_sensors > MAX_SENSORS)
+               loongson_sysconf.nr_sensors = 0;
+       if (loongson_sysconf.nr_sensors)
+               memcpy(loongson_sysconf.sensors, esys->sensors,
+                       sizeof(struct sensor_device) * loongson_sysconf.nr_sensors);
+       pr_info("CpuClock = %u\n", cpu_clock_freq);
+}
diff --git a/arch/mips/loongson64/hpet.c b/arch/mips/loongson64/hpet.c
new file mode 100644 (file)
index 0000000..ed15430
--- /dev/null
@@ -0,0 +1,289 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/percpu.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+
+#include <asm/hpet.h>
+#include <asm/time.h>
+
+#define SMBUS_CFG_BASE         (loongson_sysconf.ht_control_base + 0x0300a000)
+#define SMBUS_PCI_REG40                0x40
+#define SMBUS_PCI_REG64                0x64
+#define SMBUS_PCI_REGB4                0xb4
+
+#define HPET_MIN_CYCLES                16
+#define HPET_MIN_PROG_DELTA    (HPET_MIN_CYCLES * 12)
+
+static DEFINE_SPINLOCK(hpet_lock);
+DEFINE_PER_CPU(struct clock_event_device, hpet_clockevent_device);
+
+static unsigned int smbus_read(int offset)
+{
+       return *(volatile unsigned int *)(SMBUS_CFG_BASE + offset);
+}
+
+static void smbus_write(int offset, int data)
+{
+       *(volatile unsigned int *)(SMBUS_CFG_BASE + offset) = data;
+}
+
+static void smbus_enable(int offset, int bit)
+{
+       unsigned int cfg = smbus_read(offset);
+
+       cfg |= bit;
+       smbus_write(offset, cfg);
+}
+
+static int hpet_read(int offset)
+{
+       return *(volatile unsigned int *)(HPET_MMIO_ADDR + offset);
+}
+
+static void hpet_write(int offset, int data)
+{
+       *(volatile unsigned int *)(HPET_MMIO_ADDR + offset) = data;
+}
+
+static void hpet_start_counter(void)
+{
+       unsigned int cfg = hpet_read(HPET_CFG);
+
+       cfg |= HPET_CFG_ENABLE;
+       hpet_write(HPET_CFG, cfg);
+}
+
+static void hpet_stop_counter(void)
+{
+       unsigned int cfg = hpet_read(HPET_CFG);
+
+       cfg &= ~HPET_CFG_ENABLE;
+       hpet_write(HPET_CFG, cfg);
+}
+
+static void hpet_reset_counter(void)
+{
+       hpet_write(HPET_COUNTER, 0);
+       hpet_write(HPET_COUNTER + 4, 0);
+}
+
+static void hpet_restart_counter(void)
+{
+       hpet_stop_counter();
+       hpet_reset_counter();
+       hpet_start_counter();
+}
+
+static void hpet_enable_legacy_int(void)
+{
+       /* Do nothing on Loongson-3 */
+}
+
+static int hpet_set_state_periodic(struct clock_event_device *evt)
+{
+       int cfg;
+
+       spin_lock(&hpet_lock);
+
+       pr_info("set clock event to periodic mode!\n");
+       /* stop counter */
+       hpet_stop_counter();
+
+       /* enables the timer0 to generate a periodic interrupt */
+       cfg = hpet_read(HPET_T0_CFG);
+       cfg &= ~HPET_TN_LEVEL;
+       cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL |
+               HPET_TN_32BIT;
+       hpet_write(HPET_T0_CFG, cfg);
+
+       /* set the comparator */
+       hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL);
+       udelay(1);
+       hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL);
+
+       /* start counter */
+       hpet_start_counter();
+
+       spin_unlock(&hpet_lock);
+       return 0;
+}
+
+static int hpet_set_state_shutdown(struct clock_event_device *evt)
+{
+       int cfg;
+
+       spin_lock(&hpet_lock);
+
+       cfg = hpet_read(HPET_T0_CFG);
+       cfg &= ~HPET_TN_ENABLE;
+       hpet_write(HPET_T0_CFG, cfg);
+
+       spin_unlock(&hpet_lock);
+       return 0;
+}
+
+static int hpet_set_state_oneshot(struct clock_event_device *evt)
+{
+       int cfg;
+
+       spin_lock(&hpet_lock);
+
+       pr_info("set clock event to one shot mode!\n");
+       cfg = hpet_read(HPET_T0_CFG);
+       /*
+        * set timer0 type
+        * 1 : periodic interrupt
+        * 0 : non-periodic(oneshot) interrupt
+        */
+       cfg &= ~HPET_TN_PERIODIC;
+       cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
+       hpet_write(HPET_T0_CFG, cfg);
+
+       spin_unlock(&hpet_lock);
+       return 0;
+}
+
+static int hpet_tick_resume(struct clock_event_device *evt)
+{
+       spin_lock(&hpet_lock);
+       hpet_enable_legacy_int();
+       spin_unlock(&hpet_lock);
+
+       return 0;
+}
+
+static int hpet_next_event(unsigned long delta,
+               struct clock_event_device *evt)
+{
+       u32 cnt;
+       s32 res;
+
+       cnt = hpet_read(HPET_COUNTER);
+       cnt += (u32) delta;
+       hpet_write(HPET_T0_CMP, cnt);
+
+       res = (s32)(cnt - hpet_read(HPET_COUNTER));
+
+       return res < HPET_MIN_CYCLES ? -ETIME : 0;
+}
+
+static irqreturn_t hpet_irq_handler(int irq, void *data)
+{
+       int is_irq;
+       struct clock_event_device *cd;
+       unsigned int cpu = smp_processor_id();
+
+       is_irq = hpet_read(HPET_STATUS);
+       if (is_irq & HPET_T0_IRS) {
+               /* clear the TIMER0 irq status register */
+               hpet_write(HPET_STATUS, HPET_T0_IRS);
+               cd = &per_cpu(hpet_clockevent_device, cpu);
+               cd->event_handler(cd);
+               return IRQ_HANDLED;
+       }
+       return IRQ_NONE;
+}
+
+static struct irqaction hpet_irq = {
+       .handler = hpet_irq_handler,
+       .flags = IRQF_NOBALANCING | IRQF_TIMER,
+       .name = "hpet",
+};
+
+/*
+ * hpet address assignation and irq setting should be done in bios.
+ * but pmon don't do this, we just setup here directly.
+ * The operation under is normal. unfortunately, hpet_setup process
+ * is before pci initialize.
+ *
+ * {
+ *     struct pci_dev *pdev;
+ *
+ *     pdev = pci_get_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL);
+ *     pci_write_config_word(pdev, SMBUS_PCI_REGB4, HPET_ADDR);
+ *
+ *     ...
+ * }
+ */
+static void hpet_setup(void)
+{
+       /* set hpet base address */
+       smbus_write(SMBUS_PCI_REGB4, HPET_ADDR);
+
+       /* enable decoding of access to HPET MMIO*/
+       smbus_enable(SMBUS_PCI_REG40, (1 << 28));
+
+       /* HPET irq enable */
+       smbus_enable(SMBUS_PCI_REG64, (1 << 10));
+
+       hpet_enable_legacy_int();
+}
+
+void __init setup_hpet_timer(void)
+{
+       unsigned int cpu = smp_processor_id();
+       struct clock_event_device *cd;
+
+       hpet_setup();
+
+       cd = &per_cpu(hpet_clockevent_device, cpu);
+       cd->name = "hpet";
+       cd->rating = 100;
+       cd->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+       cd->set_state_shutdown = hpet_set_state_shutdown;
+       cd->set_state_periodic = hpet_set_state_periodic;
+       cd->set_state_oneshot = hpet_set_state_oneshot;
+       cd->tick_resume = hpet_tick_resume;
+       cd->set_next_event = hpet_next_event;
+       cd->irq = HPET_T0_IRQ;
+       cd->cpumask = cpumask_of(cpu);
+       clockevent_set_clock(cd, HPET_FREQ);
+       cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
+       cd->max_delta_ticks = 0x7fffffff;
+       cd->min_delta_ns = clockevent_delta2ns(HPET_MIN_PROG_DELTA, cd);
+       cd->min_delta_ticks = HPET_MIN_PROG_DELTA;
+
+       clockevents_register_device(cd);
+       setup_irq(HPET_T0_IRQ, &hpet_irq);
+       pr_info("hpet clock event device register\n");
+}
+
+static u64 hpet_read_counter(struct clocksource *cs)
+{
+       return (u64)hpet_read(HPET_COUNTER);
+}
+
+static void hpet_suspend(struct clocksource *cs)
+{
+}
+
+static void hpet_resume(struct clocksource *cs)
+{
+       hpet_setup();
+       hpet_restart_counter();
+}
+
+static struct clocksource csrc_hpet = {
+       .name = "hpet",
+       /* mips clocksource rating is less than 300, so hpet is better. */
+       .rating = 300,
+       .read = hpet_read_counter,
+       .mask = CLOCKSOURCE_MASK(32),
+       /* oneshot mode work normal with this flag */
+       .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+       .suspend = hpet_suspend,
+       .resume = hpet_resume,
+       .mult = 0,
+       .shift = 10,
+};
+
+int __init init_hpet_clocksource(void)
+{
+       csrc_hpet.mult = clocksource_hz2mult(HPET_FREQ, csrc_hpet.shift);
+       return clocksource_register_hz(&csrc_hpet, HPET_FREQ);
+}
+
+arch_initcall(init_hpet_clocksource);
diff --git a/arch/mips/loongson64/init.c b/arch/mips/loongson64/init.c
new file mode 100644 (file)
index 0000000..48b44f4
--- /dev/null
@@ -0,0 +1,45 @@
+// 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 <loongson.h>
+
+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)
+{
+       prom_init_cmdline();
+       prom_init_env();
+
+       /* init base address of io space */
+       set_io_port_base((unsigned long)
+               ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE));
+
+       prom_init_numa_memory();
+
+       /* Hardcode to CPU UART 0 */
+       setup_8250_early_printk_port(TO_UNCAC(LOONGSON_REG_BASE + 0x1e0), 0, 1024);
+
+       register_smp_ops(&loongson3_smp_ops);
+       board_nmi_handler_setup = mips_nmi_setup;
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
diff --git a/arch/mips/loongson64/irq.c b/arch/mips/loongson64/irq.c
new file mode 100644 (file)
index 0000000..79ad797
--- /dev/null
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <loongson.h>
+#include <irq.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/i8259.h>
+#include <asm/mipsregs.h>
+
+#include "smp.h"
+
+extern void loongson3_send_irq_by_ipi(int cpu, int irqs);
+
+unsigned int irq_cpu[16] = {[0 ... 15] = -1};
+unsigned int ht_irq[] = {0, 1, 3, 4, 5, 6, 7, 8, 12, 14, 15};
+unsigned int local_irq = 1<<0 | 1<<1 | 1<<2 | 1<<7 | 1<<8 | 1<<12;
+
+int plat_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity,
+                         bool force)
+{
+       unsigned int cpu;
+       struct cpumask new_affinity;
+
+       /* I/O devices are connected on package-0 */
+       cpumask_copy(&new_affinity, affinity);
+       for_each_cpu(cpu, affinity)
+               if (cpu_data[cpu].package > 0)
+                       cpumask_clear_cpu(cpu, &new_affinity);
+
+       if (cpumask_empty(&new_affinity))
+               return -EINVAL;
+
+       cpumask_copy(d->common->affinity, &new_affinity);
+
+       return IRQ_SET_MASK_OK_NOCOPY;
+}
+
+static void ht_irqdispatch(void)
+{
+       unsigned int i, irq;
+       struct irq_data *irqd;
+       struct cpumask affinity;
+
+       irq = LOONGSON_HT1_INT_VECTOR(0);
+       LOONGSON_HT1_INT_VECTOR(0) = irq; /* Acknowledge the IRQs */
+
+       for (i = 0; i < ARRAY_SIZE(ht_irq); i++) {
+               if (!(irq & (0x1 << ht_irq[i])))
+                       continue;
+
+               /* handled by local core */
+               if (local_irq & (0x1 << ht_irq[i])) {
+                       do_IRQ(ht_irq[i]);
+                       continue;
+               }
+
+               irqd = irq_get_irq_data(ht_irq[i]);
+               cpumask_and(&affinity, irqd->common->affinity, cpu_active_mask);
+               if (cpumask_empty(&affinity)) {
+                       do_IRQ(ht_irq[i]);
+                       continue;
+               }
+
+               irq_cpu[ht_irq[i]] = cpumask_next(irq_cpu[ht_irq[i]], &affinity);
+               if (irq_cpu[ht_irq[i]] >= nr_cpu_ids)
+                       irq_cpu[ht_irq[i]] = cpumask_first(&affinity);
+
+               if (irq_cpu[ht_irq[i]] == 0) {
+                       do_IRQ(ht_irq[i]);
+                       continue;
+               }
+
+               /* balanced by other cores */
+               loongson3_send_irq_by_ipi(irq_cpu[ht_irq[i]], (0x1 << ht_irq[i]));
+       }
+}
+
+#define UNUSED_IPS (CAUSEF_IP5 | CAUSEF_IP4 | CAUSEF_IP1 | CAUSEF_IP0)
+
+asmlinkage void plat_irq_dispatch(void)
+{
+       unsigned int pending;
+
+       pending = read_c0_cause() & read_c0_status() & ST0_IM;
+
+       if (pending & CAUSEF_IP7)
+               do_IRQ(LOONGSON_TIMER_IRQ);
+#if defined(CONFIG_SMP)
+       if (pending & CAUSEF_IP6)
+               loongson3_ipi_interrupt(NULL);
+#endif
+       if (pending & CAUSEF_IP3)
+               ht_irqdispatch();
+       if (pending & CAUSEF_IP2)
+               do_IRQ(LOONGSON_UART_IRQ);
+       if (pending & UNUSED_IPS) {
+               pr_err("%s : spurious interrupt\n", __func__);
+               spurious_interrupt();
+       }
+}
+
+static inline void mask_loongson_irq(struct irq_data *d) { }
+static inline void unmask_loongson_irq(struct irq_data *d) { }
+
+ /* For MIPS IRQs which shared by all cores */
+static struct irq_chip loongson_irq_chip = {
+       .name           = "Loongson",
+       .irq_ack        = mask_loongson_irq,
+       .irq_mask       = mask_loongson_irq,
+       .irq_mask_ack   = mask_loongson_irq,
+       .irq_unmask     = unmask_loongson_irq,
+       .irq_eoi        = unmask_loongson_irq,
+};
+
+void irq_router_init(void)
+{
+       int i;
+
+       /* route LPC int to cpu core0 int 0 */
+       LOONGSON_INT_ROUTER_LPC =
+               LOONGSON_INT_COREx_INTy(loongson_sysconf.boot_cpu_id, 0);
+       /* route HT1 int0 ~ int7 to cpu core0 INT1*/
+       for (i = 0; i < 8; i++)
+               LOONGSON_INT_ROUTER_HT1(i) =
+                       LOONGSON_INT_COREx_INTy(loongson_sysconf.boot_cpu_id, 1);
+       /* enable HT1 interrupt */
+       LOONGSON_HT1_INTN_EN(0) = 0xffffffff;
+       /* enable router interrupt intenset */
+       LOONGSON_INT_ROUTER_INTENSET =
+               LOONGSON_INT_ROUTER_INTEN | (0xffff << 16) | 0x1 << 10;
+}
+
+void __init arch_init_irq(void)
+{
+       struct irq_chip *chip;
+
+       clear_c0_status(ST0_IM | ST0_BEV);
+
+       irq_router_init();
+       mips_cpu_irq_init();
+       init_i8259_irqs();
+       chip = irq_get_chip(I8259A_IRQ_BASE);
+       chip->irq_set_affinity = plat_set_irq_affinity;
+
+       irq_set_chip_and_handler(LOONGSON_UART_IRQ,
+                       &loongson_irq_chip, handle_percpu_irq);
+       irq_set_chip_and_handler(LOONGSON_BRIDGE_IRQ,
+                       &loongson_irq_chip, handle_percpu_irq);
+
+       set_c0_status(STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP6);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+void fixup_irqs(void)
+{
+       irq_cpu_offline();
+       clear_c0_status(ST0_IM);
+}
+
+#endif
diff --git a/arch/mips/loongson64/loongson-3/Makefile b/arch/mips/loongson64/loongson-3/Makefile
deleted file mode 100644 (file)
index df39598..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for Loongson-3 family machines
-#
-obj-y                  += irq.o cop2-ex.o platform.o acpi_init.o dma.o
-
-obj-$(CONFIG_SMP)      += smp.o
-
-obj-$(CONFIG_NUMA)     += numa.o
-
-obj-$(CONFIG_RS780_HPET) += hpet.o
diff --git a/arch/mips/loongson64/loongson-3/acpi_init.c b/arch/mips/loongson64/loongson-3/acpi_init.c
deleted file mode 100644 (file)
index 8d7c119..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/io.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/export.h>
-
-#define SBX00_ACPI_IO_BASE 0x800
-#define SBX00_ACPI_IO_SIZE 0x100
-
-#define ACPI_PM_EVT_BLK         (SBX00_ACPI_IO_BASE + 0x00) /* 4 bytes */
-#define ACPI_PM_CNT_BLK         (SBX00_ACPI_IO_BASE + 0x04) /* 2 bytes */
-#define ACPI_PMA_CNT_BLK        (SBX00_ACPI_IO_BASE + 0x0F) /* 1 byte */
-#define ACPI_PM_TMR_BLK         (SBX00_ACPI_IO_BASE + 0x18) /* 4 bytes */
-#define ACPI_GPE0_BLK           (SBX00_ACPI_IO_BASE + 0x10) /* 8 bytes */
-#define ACPI_END                (SBX00_ACPI_IO_BASE + 0x80)
-
-#define PM_INDEX        0xCD6
-#define PM_DATA         0xCD7
-#define PM2_INDEX       0xCD0
-#define PM2_DATA        0xCD1
-
-/*
- * SCI interrupt need acpi space, allocate here
- */
-
-static int __init register_acpi_resource(void)
-{
-       request_region(SBX00_ACPI_IO_BASE, SBX00_ACPI_IO_SIZE, "acpi");
-       return 0;
-}
-
-static void pmio_write_index(u16 index, u8 reg, u8 value)
-{
-       outb(reg, index);
-       outb(value, index + 1);
-}
-
-static u8 pmio_read_index(u16 index, u8 reg)
-{
-       outb(reg, index);
-       return inb(index + 1);
-}
-
-void pm_iowrite(u8 reg, u8 value)
-{
-       pmio_write_index(PM_INDEX, reg, value);
-}
-EXPORT_SYMBOL(pm_iowrite);
-
-u8 pm_ioread(u8 reg)
-{
-       return pmio_read_index(PM_INDEX, reg);
-}
-EXPORT_SYMBOL(pm_ioread);
-
-void pm2_iowrite(u8 reg, u8 value)
-{
-       pmio_write_index(PM2_INDEX, reg, value);
-}
-EXPORT_SYMBOL(pm2_iowrite);
-
-u8 pm2_ioread(u8 reg)
-{
-       return pmio_read_index(PM2_INDEX, reg);
-}
-EXPORT_SYMBOL(pm2_ioread);
-
-static void acpi_hw_clear_status(void)
-{
-       u16 value;
-
-       /* PMStatus: Clear WakeStatus/PwrBtnStatus */
-       value = inw(ACPI_PM_EVT_BLK);
-       value |= (1 << 8 | 1 << 15);
-       outw(value, ACPI_PM_EVT_BLK);
-
-       /* GPEStatus: Clear all generated events */
-       outl(inl(ACPI_GPE0_BLK), ACPI_GPE0_BLK);
-}
-
-void acpi_registers_setup(void)
-{
-       u32 value;
-
-       /* PM Status Base */
-       pm_iowrite(0x20, ACPI_PM_EVT_BLK & 0xff);
-       pm_iowrite(0x21, ACPI_PM_EVT_BLK >> 8);
-
-       /* PM Control Base */
-       pm_iowrite(0x22, ACPI_PM_CNT_BLK & 0xff);
-       pm_iowrite(0x23, ACPI_PM_CNT_BLK >> 8);
-
-       /* GPM Base */
-       pm_iowrite(0x28, ACPI_GPE0_BLK & 0xff);
-       pm_iowrite(0x29, ACPI_GPE0_BLK >> 8);
-
-       /* ACPI End */
-       pm_iowrite(0x2e, ACPI_END & 0xff);
-       pm_iowrite(0x2f, ACPI_END >> 8);
-
-       /* IO Decode: When AcpiDecodeEnable set, South-Bridge uses the contents
-        * of the PM registers at index 0x20~0x2B to decode ACPI I/O address. */
-       pm_iowrite(0x0e, 1 << 3);
-
-       /* SCI_EN set */
-       outw(1, ACPI_PM_CNT_BLK);
-
-       /* Enable to generate SCI */
-       pm_iowrite(0x10, pm_ioread(0x10) | 1);
-
-       /* GPM3/GPM9 enable */
-       value = inl(ACPI_GPE0_BLK + 4);
-       outl(value | (1 << 14) | (1 << 22), ACPI_GPE0_BLK + 4);
-
-       /* Set GPM9 as input */
-       pm_iowrite(0x8d, pm_ioread(0x8d) & (~(1 << 1)));
-
-       /* Set GPM9 as non-output */
-       pm_iowrite(0x94, pm_ioread(0x94) | (1 << 3));
-
-       /* GPM3 config ACPI trigger SCIOUT */
-       pm_iowrite(0x33, pm_ioread(0x33) & (~(3 << 4)));
-
-       /* GPM9 config ACPI trigger SCIOUT */
-       pm_iowrite(0x3d, pm_ioread(0x3d) & (~(3 << 2)));
-
-       /* GPM3 config falling edge trigger */
-       pm_iowrite(0x37, pm_ioread(0x37) & (~(1 << 6)));
-
-       /* No wait for STPGNT# in ACPI Sx state */
-       pm_iowrite(0x7c, pm_ioread(0x7c) | (1 << 6));
-
-       /* Set GPM3 pull-down enable */
-       value = pm2_ioread(0xf6);
-       value |= ((1 << 7) | (1 << 3));
-       pm2_iowrite(0xf6, value);
-
-       /* Set GPM9 pull-down enable */
-       value = pm2_ioread(0xf8);
-       value |= ((1 << 5) | (1 << 1));
-       pm2_iowrite(0xf8, value);
-}
-
-int __init sbx00_acpi_init(void)
-{
-       register_acpi_resource();
-       acpi_registers_setup();
-       acpi_hw_clear_status();
-
-       return 0;
-}
diff --git a/arch/mips/loongson64/loongson-3/cop2-ex.c b/arch/mips/loongson64/loongson-3/cop2-ex.c
deleted file mode 100644 (file)
index 9efdfe4..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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) 2014 Lemote Corporation.
- *   written by Huacai Chen <chenhc@lemote.com>
- *
- * based on arch/mips/cavium-octeon/cpu.c
- * Copyright (C) 2009 Wind River Systems,
- *   written by Ralf Baechle <ralf@linux-mips.org>
- */
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/notifier.h>
-#include <linux/ptrace.h>
-
-#include <asm/fpu.h>
-#include <asm/cop2.h>
-#include <asm/current.h>
-#include <asm/mipsregs.h>
-
-static int loongson_cu2_call(struct notifier_block *nfb, unsigned long action,
-       void *data)
-{
-       int fpu_owned;
-       int fr = !test_thread_flag(TIF_32BIT_FPREGS);
-
-       switch (action) {
-       case CU2_EXCEPTION:
-               preempt_disable();
-               fpu_owned = __is_fpu_owner();
-               if (!fr)
-                       set_c0_status(ST0_CU1 | ST0_CU2);
-               else
-                       set_c0_status(ST0_CU1 | ST0_CU2 | ST0_FR);
-               enable_fpu_hazard();
-               KSTK_STATUS(current) |= (ST0_CU1 | ST0_CU2);
-               if (fr)
-                       KSTK_STATUS(current) |= ST0_FR;
-               else
-                       KSTK_STATUS(current) &= ~ST0_FR;
-               /* If FPU is owned, we needn't init or restore fp */
-               if (!fpu_owned) {
-                       set_thread_flag(TIF_USEDFPU);
-                       init_fp_ctx(current);
-                       _restore_fp(current);
-               }
-               preempt_enable();
-
-               return NOTIFY_STOP;     /* Don't call default notifier */
-       }
-
-       return NOTIFY_OK;               /* Let default notifier send signals */
-}
-
-static int __init loongson_cu2_setup(void)
-{
-       return cu2_notifier(loongson_cu2_call, 0);
-}
-early_initcall(loongson_cu2_setup);
diff --git a/arch/mips/loongson64/loongson-3/dma.c b/arch/mips/loongson64/loongson-3/dma.c
deleted file mode 100644 (file)
index 5e86635..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/dma-direct.h>
-#include <linux/init.h>
-#include <linux/swiotlb.h>
-
-dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr)
-{
-       /* We extract 2bit node id (bit 44~47, only bit 44~45 used now) from
-        * Loongson-3's 48bit address space and embed it into 40bit */
-       long nid = (paddr >> 44) & 0x3;
-       return ((nid << 44) ^ paddr) | (nid << 37);
-}
-
-phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr)
-{
-       /* We extract 2bit node id (bit 44~47, only bit 44~45 used now) from
-        * Loongson-3's 48bit address space and embed it into 40bit */
-       long nid = (daddr >> 37) & 0x3;
-       return ((nid << 37) ^ daddr) | (nid << 44);
-}
-
-void __init plat_swiotlb_setup(void)
-{
-       swiotlb_init(1);
-}
diff --git a/arch/mips/loongson64/loongson-3/hpet.c b/arch/mips/loongson64/loongson-3/hpet.c
deleted file mode 100644 (file)
index ed15430..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/percpu.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-
-#include <asm/hpet.h>
-#include <asm/time.h>
-
-#define SMBUS_CFG_BASE         (loongson_sysconf.ht_control_base + 0x0300a000)
-#define SMBUS_PCI_REG40                0x40
-#define SMBUS_PCI_REG64                0x64
-#define SMBUS_PCI_REGB4                0xb4
-
-#define HPET_MIN_CYCLES                16
-#define HPET_MIN_PROG_DELTA    (HPET_MIN_CYCLES * 12)
-
-static DEFINE_SPINLOCK(hpet_lock);
-DEFINE_PER_CPU(struct clock_event_device, hpet_clockevent_device);
-
-static unsigned int smbus_read(int offset)
-{
-       return *(volatile unsigned int *)(SMBUS_CFG_BASE + offset);
-}
-
-static void smbus_write(int offset, int data)
-{
-       *(volatile unsigned int *)(SMBUS_CFG_BASE + offset) = data;
-}
-
-static void smbus_enable(int offset, int bit)
-{
-       unsigned int cfg = smbus_read(offset);
-
-       cfg |= bit;
-       smbus_write(offset, cfg);
-}
-
-static int hpet_read(int offset)
-{
-       return *(volatile unsigned int *)(HPET_MMIO_ADDR + offset);
-}
-
-static void hpet_write(int offset, int data)
-{
-       *(volatile unsigned int *)(HPET_MMIO_ADDR + offset) = data;
-}
-
-static void hpet_start_counter(void)
-{
-       unsigned int cfg = hpet_read(HPET_CFG);
-
-       cfg |= HPET_CFG_ENABLE;
-       hpet_write(HPET_CFG, cfg);
-}
-
-static void hpet_stop_counter(void)
-{
-       unsigned int cfg = hpet_read(HPET_CFG);
-
-       cfg &= ~HPET_CFG_ENABLE;
-       hpet_write(HPET_CFG, cfg);
-}
-
-static void hpet_reset_counter(void)
-{
-       hpet_write(HPET_COUNTER, 0);
-       hpet_write(HPET_COUNTER + 4, 0);
-}
-
-static void hpet_restart_counter(void)
-{
-       hpet_stop_counter();
-       hpet_reset_counter();
-       hpet_start_counter();
-}
-
-static void hpet_enable_legacy_int(void)
-{
-       /* Do nothing on Loongson-3 */
-}
-
-static int hpet_set_state_periodic(struct clock_event_device *evt)
-{
-       int cfg;
-
-       spin_lock(&hpet_lock);
-
-       pr_info("set clock event to periodic mode!\n");
-       /* stop counter */
-       hpet_stop_counter();
-
-       /* enables the timer0 to generate a periodic interrupt */
-       cfg = hpet_read(HPET_T0_CFG);
-       cfg &= ~HPET_TN_LEVEL;
-       cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL |
-               HPET_TN_32BIT;
-       hpet_write(HPET_T0_CFG, cfg);
-
-       /* set the comparator */
-       hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL);
-       udelay(1);
-       hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL);
-
-       /* start counter */
-       hpet_start_counter();
-
-       spin_unlock(&hpet_lock);
-       return 0;
-}
-
-static int hpet_set_state_shutdown(struct clock_event_device *evt)
-{
-       int cfg;
-
-       spin_lock(&hpet_lock);
-
-       cfg = hpet_read(HPET_T0_CFG);
-       cfg &= ~HPET_TN_ENABLE;
-       hpet_write(HPET_T0_CFG, cfg);
-
-       spin_unlock(&hpet_lock);
-       return 0;
-}
-
-static int hpet_set_state_oneshot(struct clock_event_device *evt)
-{
-       int cfg;
-
-       spin_lock(&hpet_lock);
-
-       pr_info("set clock event to one shot mode!\n");
-       cfg = hpet_read(HPET_T0_CFG);
-       /*
-        * set timer0 type
-        * 1 : periodic interrupt
-        * 0 : non-periodic(oneshot) interrupt
-        */
-       cfg &= ~HPET_TN_PERIODIC;
-       cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
-       hpet_write(HPET_T0_CFG, cfg);
-
-       spin_unlock(&hpet_lock);
-       return 0;
-}
-
-static int hpet_tick_resume(struct clock_event_device *evt)
-{
-       spin_lock(&hpet_lock);
-       hpet_enable_legacy_int();
-       spin_unlock(&hpet_lock);
-
-       return 0;
-}
-
-static int hpet_next_event(unsigned long delta,
-               struct clock_event_device *evt)
-{
-       u32 cnt;
-       s32 res;
-
-       cnt = hpet_read(HPET_COUNTER);
-       cnt += (u32) delta;
-       hpet_write(HPET_T0_CMP, cnt);
-
-       res = (s32)(cnt - hpet_read(HPET_COUNTER));
-
-       return res < HPET_MIN_CYCLES ? -ETIME : 0;
-}
-
-static irqreturn_t hpet_irq_handler(int irq, void *data)
-{
-       int is_irq;
-       struct clock_event_device *cd;
-       unsigned int cpu = smp_processor_id();
-
-       is_irq = hpet_read(HPET_STATUS);
-       if (is_irq & HPET_T0_IRS) {
-               /* clear the TIMER0 irq status register */
-               hpet_write(HPET_STATUS, HPET_T0_IRS);
-               cd = &per_cpu(hpet_clockevent_device, cpu);
-               cd->event_handler(cd);
-               return IRQ_HANDLED;
-       }
-       return IRQ_NONE;
-}
-
-static struct irqaction hpet_irq = {
-       .handler = hpet_irq_handler,
-       .flags = IRQF_NOBALANCING | IRQF_TIMER,
-       .name = "hpet",
-};
-
-/*
- * hpet address assignation and irq setting should be done in bios.
- * but pmon don't do this, we just setup here directly.
- * The operation under is normal. unfortunately, hpet_setup process
- * is before pci initialize.
- *
- * {
- *     struct pci_dev *pdev;
- *
- *     pdev = pci_get_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL);
- *     pci_write_config_word(pdev, SMBUS_PCI_REGB4, HPET_ADDR);
- *
- *     ...
- * }
- */
-static void hpet_setup(void)
-{
-       /* set hpet base address */
-       smbus_write(SMBUS_PCI_REGB4, HPET_ADDR);
-
-       /* enable decoding of access to HPET MMIO*/
-       smbus_enable(SMBUS_PCI_REG40, (1 << 28));
-
-       /* HPET irq enable */
-       smbus_enable(SMBUS_PCI_REG64, (1 << 10));
-
-       hpet_enable_legacy_int();
-}
-
-void __init setup_hpet_timer(void)
-{
-       unsigned int cpu = smp_processor_id();
-       struct clock_event_device *cd;
-
-       hpet_setup();
-
-       cd = &per_cpu(hpet_clockevent_device, cpu);
-       cd->name = "hpet";
-       cd->rating = 100;
-       cd->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
-       cd->set_state_shutdown = hpet_set_state_shutdown;
-       cd->set_state_periodic = hpet_set_state_periodic;
-       cd->set_state_oneshot = hpet_set_state_oneshot;
-       cd->tick_resume = hpet_tick_resume;
-       cd->set_next_event = hpet_next_event;
-       cd->irq = HPET_T0_IRQ;
-       cd->cpumask = cpumask_of(cpu);
-       clockevent_set_clock(cd, HPET_FREQ);
-       cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
-       cd->max_delta_ticks = 0x7fffffff;
-       cd->min_delta_ns = clockevent_delta2ns(HPET_MIN_PROG_DELTA, cd);
-       cd->min_delta_ticks = HPET_MIN_PROG_DELTA;
-
-       clockevents_register_device(cd);
-       setup_irq(HPET_T0_IRQ, &hpet_irq);
-       pr_info("hpet clock event device register\n");
-}
-
-static u64 hpet_read_counter(struct clocksource *cs)
-{
-       return (u64)hpet_read(HPET_COUNTER);
-}
-
-static void hpet_suspend(struct clocksource *cs)
-{
-}
-
-static void hpet_resume(struct clocksource *cs)
-{
-       hpet_setup();
-       hpet_restart_counter();
-}
-
-static struct clocksource csrc_hpet = {
-       .name = "hpet",
-       /* mips clocksource rating is less than 300, so hpet is better. */
-       .rating = 300,
-       .read = hpet_read_counter,
-       .mask = CLOCKSOURCE_MASK(32),
-       /* oneshot mode work normal with this flag */
-       .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-       .suspend = hpet_suspend,
-       .resume = hpet_resume,
-       .mult = 0,
-       .shift = 10,
-};
-
-int __init init_hpet_clocksource(void)
-{
-       csrc_hpet.mult = clocksource_hz2mult(HPET_FREQ, csrc_hpet.shift);
-       return clocksource_register_hz(&csrc_hpet, HPET_FREQ);
-}
-
-arch_initcall(init_hpet_clocksource);
diff --git a/arch/mips/loongson64/loongson-3/irq.c b/arch/mips/loongson64/loongson-3/irq.c
deleted file mode 100644 (file)
index 79ad797..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <loongson.h>
-#include <irq.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-
-#include <asm/irq_cpu.h>
-#include <asm/i8259.h>
-#include <asm/mipsregs.h>
-
-#include "smp.h"
-
-extern void loongson3_send_irq_by_ipi(int cpu, int irqs);
-
-unsigned int irq_cpu[16] = {[0 ... 15] = -1};
-unsigned int ht_irq[] = {0, 1, 3, 4, 5, 6, 7, 8, 12, 14, 15};
-unsigned int local_irq = 1<<0 | 1<<1 | 1<<2 | 1<<7 | 1<<8 | 1<<12;
-
-int plat_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity,
-                         bool force)
-{
-       unsigned int cpu;
-       struct cpumask new_affinity;
-
-       /* I/O devices are connected on package-0 */
-       cpumask_copy(&new_affinity, affinity);
-       for_each_cpu(cpu, affinity)
-               if (cpu_data[cpu].package > 0)
-                       cpumask_clear_cpu(cpu, &new_affinity);
-
-       if (cpumask_empty(&new_affinity))
-               return -EINVAL;
-
-       cpumask_copy(d->common->affinity, &new_affinity);
-
-       return IRQ_SET_MASK_OK_NOCOPY;
-}
-
-static void ht_irqdispatch(void)
-{
-       unsigned int i, irq;
-       struct irq_data *irqd;
-       struct cpumask affinity;
-
-       irq = LOONGSON_HT1_INT_VECTOR(0);
-       LOONGSON_HT1_INT_VECTOR(0) = irq; /* Acknowledge the IRQs */
-
-       for (i = 0; i < ARRAY_SIZE(ht_irq); i++) {
-               if (!(irq & (0x1 << ht_irq[i])))
-                       continue;
-
-               /* handled by local core */
-               if (local_irq & (0x1 << ht_irq[i])) {
-                       do_IRQ(ht_irq[i]);
-                       continue;
-               }
-
-               irqd = irq_get_irq_data(ht_irq[i]);
-               cpumask_and(&affinity, irqd->common->affinity, cpu_active_mask);
-               if (cpumask_empty(&affinity)) {
-                       do_IRQ(ht_irq[i]);
-                       continue;
-               }
-
-               irq_cpu[ht_irq[i]] = cpumask_next(irq_cpu[ht_irq[i]], &affinity);
-               if (irq_cpu[ht_irq[i]] >= nr_cpu_ids)
-                       irq_cpu[ht_irq[i]] = cpumask_first(&affinity);
-
-               if (irq_cpu[ht_irq[i]] == 0) {
-                       do_IRQ(ht_irq[i]);
-                       continue;
-               }
-
-               /* balanced by other cores */
-               loongson3_send_irq_by_ipi(irq_cpu[ht_irq[i]], (0x1 << ht_irq[i]));
-       }
-}
-
-#define UNUSED_IPS (CAUSEF_IP5 | CAUSEF_IP4 | CAUSEF_IP1 | CAUSEF_IP0)
-
-asmlinkage void plat_irq_dispatch(void)
-{
-       unsigned int pending;
-
-       pending = read_c0_cause() & read_c0_status() & ST0_IM;
-
-       if (pending & CAUSEF_IP7)
-               do_IRQ(LOONGSON_TIMER_IRQ);
-#if defined(CONFIG_SMP)
-       if (pending & CAUSEF_IP6)
-               loongson3_ipi_interrupt(NULL);
-#endif
-       if (pending & CAUSEF_IP3)
-               ht_irqdispatch();
-       if (pending & CAUSEF_IP2)
-               do_IRQ(LOONGSON_UART_IRQ);
-       if (pending & UNUSED_IPS) {
-               pr_err("%s : spurious interrupt\n", __func__);
-               spurious_interrupt();
-       }
-}
-
-static inline void mask_loongson_irq(struct irq_data *d) { }
-static inline void unmask_loongson_irq(struct irq_data *d) { }
-
- /* For MIPS IRQs which shared by all cores */
-static struct irq_chip loongson_irq_chip = {
-       .name           = "Loongson",
-       .irq_ack        = mask_loongson_irq,
-       .irq_mask       = mask_loongson_irq,
-       .irq_mask_ack   = mask_loongson_irq,
-       .irq_unmask     = unmask_loongson_irq,
-       .irq_eoi        = unmask_loongson_irq,
-};
-
-void irq_router_init(void)
-{
-       int i;
-
-       /* route LPC int to cpu core0 int 0 */
-       LOONGSON_INT_ROUTER_LPC =
-               LOONGSON_INT_COREx_INTy(loongson_sysconf.boot_cpu_id, 0);
-       /* route HT1 int0 ~ int7 to cpu core0 INT1*/
-       for (i = 0; i < 8; i++)
-               LOONGSON_INT_ROUTER_HT1(i) =
-                       LOONGSON_INT_COREx_INTy(loongson_sysconf.boot_cpu_id, 1);
-       /* enable HT1 interrupt */
-       LOONGSON_HT1_INTN_EN(0) = 0xffffffff;
-       /* enable router interrupt intenset */
-       LOONGSON_INT_ROUTER_INTENSET =
-               LOONGSON_INT_ROUTER_INTEN | (0xffff << 16) | 0x1 << 10;
-}
-
-void __init arch_init_irq(void)
-{
-       struct irq_chip *chip;
-
-       clear_c0_status(ST0_IM | ST0_BEV);
-
-       irq_router_init();
-       mips_cpu_irq_init();
-       init_i8259_irqs();
-       chip = irq_get_chip(I8259A_IRQ_BASE);
-       chip->irq_set_affinity = plat_set_irq_affinity;
-
-       irq_set_chip_and_handler(LOONGSON_UART_IRQ,
-                       &loongson_irq_chip, handle_percpu_irq);
-       irq_set_chip_and_handler(LOONGSON_BRIDGE_IRQ,
-                       &loongson_irq_chip, handle_percpu_irq);
-
-       set_c0_status(STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP6);
-}
-
-#ifdef CONFIG_HOTPLUG_CPU
-
-void fixup_irqs(void)
-{
-       irq_cpu_offline();
-       clear_c0_status(ST0_IM);
-}
-
-#endif
diff --git a/arch/mips/loongson64/loongson-3/numa.c b/arch/mips/loongson64/loongson-3/numa.c
deleted file mode 100644 (file)
index ef94a22..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2010 Loongson Inc. & Lemote Inc. &
- *                    Institute of Computing Technology
- * Author:  Xiang Gao, gaoxiang@ict.ac.cn
- *          Huacai Chen, chenhc@lemote.com
- *          Xiaofu Meng, Shuangshuang Zhang
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/mmzone.h>
-#include <linux/export.h>
-#include <linux/nodemask.h>
-#include <linux/swap.h>
-#include <linux/memblock.h>
-#include <linux/pfn.h>
-#include <linux/highmem.h>
-#include <asm/page.h>
-#include <asm/pgalloc.h>
-#include <asm/sections.h>
-#include <linux/irq.h>
-#include <asm/bootinfo.h>
-#include <asm/mc146818-time.h>
-#include <asm/time.h>
-#include <asm/wbflush.h>
-#include <boot_param.h>
-
-static struct pglist_data prealloc__node_data[MAX_NUMNODES];
-unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES];
-EXPORT_SYMBOL(__node_distances);
-struct pglist_data *__node_data[MAX_NUMNODES];
-EXPORT_SYMBOL(__node_data);
-
-cpumask_t __node_cpumask[MAX_NUMNODES];
-EXPORT_SYMBOL(__node_cpumask);
-
-static void enable_lpa(void)
-{
-       unsigned long value;
-
-       value = __read_32bit_c0_register($16, 3);
-       value |= 0x00000080;
-       __write_32bit_c0_register($16, 3, value);
-       value = __read_32bit_c0_register($16, 3);
-       pr_info("CP0_Config3: CP0 16.3 (0x%lx)\n", value);
-
-       value = __read_32bit_c0_register($5, 1);
-       value |= 0x20000000;
-       __write_32bit_c0_register($5, 1, value);
-       value = __read_32bit_c0_register($5, 1);
-       pr_info("CP0_PageGrain: CP0 5.1 (0x%lx)\n", value);
-}
-
-static void cpu_node_probe(void)
-{
-       int i;
-
-       nodes_clear(node_possible_map);
-       nodes_clear(node_online_map);
-       for (i = 0; i < loongson_sysconf.nr_nodes; i++) {
-               node_set_state(num_online_nodes(), N_POSSIBLE);
-               node_set_online(num_online_nodes());
-       }
-
-       pr_info("NUMA: Discovered %d cpus on %d nodes\n",
-               loongson_sysconf.nr_cpus, num_online_nodes());
-}
-
-static int __init compute_node_distance(int row, int col)
-{
-       int package_row = row * loongson_sysconf.cores_per_node /
-                               loongson_sysconf.cores_per_package;
-       int package_col = col * loongson_sysconf.cores_per_node /
-                               loongson_sysconf.cores_per_package;
-
-       if (col == row)
-               return 0;
-       else if (package_row == package_col)
-               return 40;
-       else
-               return 100;
-}
-
-static void __init init_topology_matrix(void)
-{
-       int row, col;
-
-       for (row = 0; row < MAX_NUMNODES; row++)
-               for (col = 0; col < MAX_NUMNODES; col++)
-                       __node_distances[row][col] = -1;
-
-       for_each_online_node(row) {
-               for_each_online_node(col) {
-                       __node_distances[row][col] =
-                               compute_node_distance(row, col);
-               }
-       }
-}
-
-static unsigned long nid_to_addroffset(unsigned int nid)
-{
-       unsigned long result;
-       switch (nid) {
-       case 0:
-       default:
-               result = NODE0_ADDRSPACE_OFFSET;
-               break;
-       case 1:
-               result = NODE1_ADDRSPACE_OFFSET;
-               break;
-       case 2:
-               result = NODE2_ADDRSPACE_OFFSET;
-               break;
-       case 3:
-               result = NODE3_ADDRSPACE_OFFSET;
-               break;
-       }
-       return result;
-}
-
-static void __init szmem(unsigned int node)
-{
-       u32 i, mem_type;
-       static unsigned long num_physpages = 0;
-       u64 node_id, node_psize, start_pfn, end_pfn, mem_start, mem_size;
-
-       /* Parse memory information and activate */
-       for (i = 0; i < loongson_memmap->nr_map; i++) {
-               node_id = loongson_memmap->map[i].node_id;
-               if (node_id != node)
-                       continue;
-
-               mem_type = loongson_memmap->map[i].mem_type;
-               mem_size = loongson_memmap->map[i].mem_size;
-               mem_start = loongson_memmap->map[i].mem_start;
-
-               switch (mem_type) {
-               case SYSTEM_RAM_LOW:
-                       start_pfn = ((node_id << 44) + mem_start) >> PAGE_SHIFT;
-                       node_psize = (mem_size << 20) >> PAGE_SHIFT;
-                       end_pfn  = start_pfn + node_psize;
-                       num_physpages += node_psize;
-                       pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
-                               (u32)node_id, mem_type, mem_start, mem_size);
-                       pr_info("       start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n",
-                               start_pfn, end_pfn, num_physpages);
-                       memblock_add_node(PFN_PHYS(start_pfn),
-                               PFN_PHYS(end_pfn - start_pfn), node);
-                       break;
-               case SYSTEM_RAM_HIGH:
-                       start_pfn = ((node_id << 44) + mem_start) >> PAGE_SHIFT;
-                       node_psize = (mem_size << 20) >> PAGE_SHIFT;
-                       end_pfn  = start_pfn + node_psize;
-                       num_physpages += node_psize;
-                       pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
-                               (u32)node_id, mem_type, mem_start, mem_size);
-                       pr_info("       start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n",
-                               start_pfn, end_pfn, num_physpages);
-                       memblock_add_node(PFN_PHYS(start_pfn),
-                               PFN_PHYS(end_pfn - start_pfn), node);
-                       break;
-               case SYSTEM_RAM_RESERVED:
-                       pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
-                               (u32)node_id, mem_type, mem_start, mem_size);
-                       memblock_reserve(((node_id << 44) + mem_start),
-                               mem_size << 20);
-                       break;
-               }
-       }
-}
-
-static void __init node_mem_init(unsigned int node)
-{
-       unsigned long node_addrspace_offset;
-       unsigned long start_pfn, end_pfn;
-
-       node_addrspace_offset = nid_to_addroffset(node);
-       pr_info("Node%d's addrspace_offset is 0x%lx\n",
-                       node, node_addrspace_offset);
-
-       get_pfn_range_for_nid(node, &start_pfn, &end_pfn);
-       pr_info("Node%d: start_pfn=0x%lx, end_pfn=0x%lx\n",
-               node, start_pfn, end_pfn);
-
-       __node_data[node] = prealloc__node_data + node;
-
-       NODE_DATA(node)->node_start_pfn = start_pfn;
-       NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn;
-
-       if (node == 0) {
-               /* kernel end address */
-               unsigned long kernel_end_pfn = PFN_UP(__pa_symbol(&_end));
-
-               /* used by finalize_initrd() */
-               max_low_pfn = end_pfn;
-
-               /* Reserve the kernel text/data/bss */
-               memblock_reserve(start_pfn << PAGE_SHIFT,
-                                ((kernel_end_pfn - start_pfn) << PAGE_SHIFT));
-
-               /* Reserve 0xfe000000~0xffffffff for RS780E integrated GPU */
-               if (node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT))
-                       memblock_reserve((node_addrspace_offset | 0xfe000000),
-                                        32 << 20);
-       }
-}
-
-static __init void prom_meminit(void)
-{
-       unsigned int node, cpu, active_cpu = 0;
-
-       cpu_node_probe();
-       init_topology_matrix();
-
-       for (node = 0; node < loongson_sysconf.nr_nodes; node++) {
-               if (node_online(node)) {
-                       szmem(node);
-                       node_mem_init(node);
-                       cpumask_clear(&__node_cpumask[node]);
-               }
-       }
-       memblocks_present();
-       max_low_pfn = PHYS_PFN(memblock_end_of_DRAM());
-
-       for (cpu = 0; cpu < loongson_sysconf.nr_cpus; cpu++) {
-               node = cpu / loongson_sysconf.cores_per_node;
-               if (node >= num_online_nodes())
-                       node = 0;
-
-               if (loongson_sysconf.reserved_cpus_mask & (1<<cpu))
-                       continue;
-
-               cpumask_set_cpu(active_cpu, &__node_cpumask[node]);
-               pr_info("NUMA: set cpumask cpu %d on node %d\n", active_cpu, node);
-
-               active_cpu++;
-       }
-}
-
-void __init paging_init(void)
-{
-       unsigned long zones_size[MAX_NR_ZONES] = {0, };
-
-       pagetable_init();
-#ifdef CONFIG_ZONE_DMA32
-       zones_size[ZONE_DMA32] = MAX_DMA32_PFN;
-#endif
-       zones_size[ZONE_NORMAL] = max_low_pfn;
-       free_area_init_nodes(zones_size);
-}
-
-void __init mem_init(void)
-{
-       high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT);
-       memblock_free_all();
-       setup_zero_pages();     /* This comes from node 0 */
-       mem_init_print_info(NULL);
-}
-
-/* All PCI device belongs to logical Node-0 */
-int pcibus_to_node(struct pci_bus *bus)
-{
-       return 0;
-}
-EXPORT_SYMBOL(pcibus_to_node);
-
-void __init prom_init_numa_memory(void)
-{
-       enable_lpa();
-       prom_meminit();
-}
-EXPORT_SYMBOL(prom_init_numa_memory);
diff --git a/arch/mips/loongson64/loongson-3/platform.c b/arch/mips/loongson64/loongson-3/platform.c
deleted file mode 100644 (file)
index 13f3404..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2009 Lemote Inc.
- * Author: Wu Zhangjin, wuzhangjin@gmail.com
- *         Xiang Yu, xiangy@lemote.com
- *         Chen Huacai, chenhc@lemote.com
- */
-
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <asm/bootinfo.h>
-#include <boot_param.h>
-#include <loongson_hwmon.h>
-#include <workarounds.h>
-
-static int __init loongson3_platform_init(void)
-{
-       int i;
-       struct platform_device *pdev;
-
-       if (loongson_sysconf.ecname[0] != '\0')
-               platform_device_register_simple(loongson_sysconf.ecname, -1, NULL, 0);
-
-       for (i = 0; i < loongson_sysconf.nr_sensors; i++) {
-               if (loongson_sysconf.sensors[i].type > SENSOR_FAN)
-                       continue;
-
-               pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
-               pdev->name = loongson_sysconf.sensors[i].name;
-               pdev->id = loongson_sysconf.sensors[i].id;
-               pdev->dev.platform_data = &loongson_sysconf.sensors[i];
-               platform_device_register(pdev);
-       }
-
-       return 0;
-}
-
-arch_initcall(loongson3_platform_init);
diff --git a/arch/mips/loongson64/loongson-3/smp.c b/arch/mips/loongson64/loongson-3/smp.c
deleted file mode 100644 (file)
index de8e074..0000000
+++ /dev/null
@@ -1,813 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2010, 2011, 2012, Lemote, Inc.
- * Author: Chen Huacai, chenhc@lemote.com
- */
-
-#include <linux/init.h>
-#include <linux/cpu.h>
-#include <linux/sched.h>
-#include <linux/sched/hotplug.h>
-#include <linux/sched/task_stack.h>
-#include <linux/smp.h>
-#include <linux/cpufreq.h>
-#include <linux/kexec.h>
-#include <asm/processor.h>
-#include <asm/time.h>
-#include <asm/clock.h>
-#include <asm/tlbflush.h>
-#include <asm/cacheflush.h>
-#include <loongson.h>
-#include <loongson_regs.h>
-#include <workarounds.h>
-
-#include "smp.h"
-
-DEFINE_PER_CPU(int, cpu_state);
-
-static void *ipi_set0_regs[16];
-static void *ipi_clear0_regs[16];
-static void *ipi_status0_regs[16];
-static void *ipi_en0_regs[16];
-static void *ipi_mailbox_buf[16];
-static uint32_t core0_c0count[NR_CPUS];
-
-/* read a 32bit value from ipi register */
-#define loongson3_ipi_read32(addr) readl(addr)
-/* read a 64bit value from ipi register */
-#define loongson3_ipi_read64(addr) readq(addr)
-/* write a 32bit value to ipi register */
-#define loongson3_ipi_write32(action, addr)    \
-       do {                                    \
-               writel(action, addr);           \
-               __wbflush();                    \
-       } while (0)
-/* write a 64bit value to ipi register */
-#define loongson3_ipi_write64(action, addr)    \
-       do {                                    \
-               writeq(action, addr);           \
-               __wbflush();                    \
-       } while (0)
-
-u32 (*ipi_read_clear)(int cpu);
-void (*ipi_write_action)(int cpu, u32 action);
-
-static u32 csr_ipi_read_clear(int cpu)
-{
-       u32 action;
-
-       /* Load the ipi register to figure out what we're supposed to do */
-       action = csr_readl(LOONGSON_CSR_IPI_STATUS);
-       /* Clear the ipi register to clear the interrupt */
-       csr_writel(action, LOONGSON_CSR_IPI_CLEAR);
-
-       return action;
-}
-
-static void csr_ipi_write_action(int cpu, u32 action)
-{
-       unsigned int irq = 0;
-
-       while ((irq = ffs(action))) {
-               uint32_t val = CSR_IPI_SEND_BLOCK;
-               val |= (irq - 1);
-               val |= (cpu << CSR_IPI_SEND_CPU_SHIFT);
-               csr_writel(val, LOONGSON_CSR_IPI_SEND);
-               action &= ~BIT(irq - 1);
-       }
-}
-
-static u32 legacy_ipi_read_clear(int cpu)
-{
-       u32 action;
-
-       /* Load the ipi register to figure out what we're supposed to do */
-       action = loongson3_ipi_read32(ipi_status0_regs[cpu_logical_map(cpu)]);
-       /* Clear the ipi register to clear the interrupt */
-       loongson3_ipi_write32(action, ipi_clear0_regs[cpu_logical_map(cpu)]);
-
-       return action;
-}
-
-static void legacy_ipi_write_action(int cpu, u32 action)
-{
-       loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu]);
-}
-
-static void csr_ipi_probe(void)
-{
-       if (cpu_has_csr() && csr_readl(LOONGSON_CSR_FEATURES) & LOONGSON_CSRF_IPI) {
-               ipi_read_clear = csr_ipi_read_clear;
-               ipi_write_action = csr_ipi_write_action;
-       } else {
-               ipi_read_clear = legacy_ipi_read_clear;
-               ipi_write_action = legacy_ipi_write_action;
-       }
-}
-
-static void ipi_set0_regs_init(void)
-{
-       ipi_set0_regs[0] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + SET0);
-       ipi_set0_regs[1] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + SET0);
-       ipi_set0_regs[2] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + SET0);
-       ipi_set0_regs[3] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + SET0);
-       ipi_set0_regs[4] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + SET0);
-       ipi_set0_regs[5] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + SET0);
-       ipi_set0_regs[6] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + SET0);
-       ipi_set0_regs[7] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + SET0);
-       ipi_set0_regs[8] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + SET0);
-       ipi_set0_regs[9] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + SET0);
-       ipi_set0_regs[10] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + SET0);
-       ipi_set0_regs[11] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + SET0);
-       ipi_set0_regs[12] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + SET0);
-       ipi_set0_regs[13] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + SET0);
-       ipi_set0_regs[14] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + SET0);
-       ipi_set0_regs[15] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + SET0);
-}
-
-static void ipi_clear0_regs_init(void)
-{
-       ipi_clear0_regs[0] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + CLEAR0);
-       ipi_clear0_regs[1] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + CLEAR0);
-       ipi_clear0_regs[2] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + CLEAR0);
-       ipi_clear0_regs[3] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + CLEAR0);
-       ipi_clear0_regs[4] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + CLEAR0);
-       ipi_clear0_regs[5] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + CLEAR0);
-       ipi_clear0_regs[6] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + CLEAR0);
-       ipi_clear0_regs[7] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + CLEAR0);
-       ipi_clear0_regs[8] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + CLEAR0);
-       ipi_clear0_regs[9] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + CLEAR0);
-       ipi_clear0_regs[10] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + CLEAR0);
-       ipi_clear0_regs[11] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + CLEAR0);
-       ipi_clear0_regs[12] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + CLEAR0);
-       ipi_clear0_regs[13] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + CLEAR0);
-       ipi_clear0_regs[14] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + CLEAR0);
-       ipi_clear0_regs[15] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + CLEAR0);
-}
-
-static void ipi_status0_regs_init(void)
-{
-       ipi_status0_regs[0] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + STATUS0);
-       ipi_status0_regs[1] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + STATUS0);
-       ipi_status0_regs[2] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + STATUS0);
-       ipi_status0_regs[3] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + STATUS0);
-       ipi_status0_regs[4] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + STATUS0);
-       ipi_status0_regs[5] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + STATUS0);
-       ipi_status0_regs[6] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + STATUS0);
-       ipi_status0_regs[7] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + STATUS0);
-       ipi_status0_regs[8] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + STATUS0);
-       ipi_status0_regs[9] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + STATUS0);
-       ipi_status0_regs[10] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + STATUS0);
-       ipi_status0_regs[11] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + STATUS0);
-       ipi_status0_regs[12] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + STATUS0);
-       ipi_status0_regs[13] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + STATUS0);
-       ipi_status0_regs[14] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + STATUS0);
-       ipi_status0_regs[15] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + STATUS0);
-}
-
-static void ipi_en0_regs_init(void)
-{
-       ipi_en0_regs[0] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + EN0);
-       ipi_en0_regs[1] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + EN0);
-       ipi_en0_regs[2] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + EN0);
-       ipi_en0_regs[3] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + EN0);
-       ipi_en0_regs[4] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + EN0);
-       ipi_en0_regs[5] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + EN0);
-       ipi_en0_regs[6] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + EN0);
-       ipi_en0_regs[7] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + EN0);
-       ipi_en0_regs[8] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + EN0);
-       ipi_en0_regs[9] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + EN0);
-       ipi_en0_regs[10] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + EN0);
-       ipi_en0_regs[11] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + EN0);
-       ipi_en0_regs[12] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + EN0);
-       ipi_en0_regs[13] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + EN0);
-       ipi_en0_regs[14] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + EN0);
-       ipi_en0_regs[15] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + EN0);
-}
-
-static void ipi_mailbox_buf_init(void)
-{
-       ipi_mailbox_buf[0] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + BUF);
-       ipi_mailbox_buf[1] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + BUF);
-       ipi_mailbox_buf[2] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + BUF);
-       ipi_mailbox_buf[3] = (void *)
-               (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + BUF);
-       ipi_mailbox_buf[4] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + BUF);
-       ipi_mailbox_buf[5] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + BUF);
-       ipi_mailbox_buf[6] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + BUF);
-       ipi_mailbox_buf[7] = (void *)
-               (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + BUF);
-       ipi_mailbox_buf[8] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + BUF);
-       ipi_mailbox_buf[9] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + BUF);
-       ipi_mailbox_buf[10] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + BUF);
-       ipi_mailbox_buf[11] = (void *)
-               (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + BUF);
-       ipi_mailbox_buf[12] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + BUF);
-       ipi_mailbox_buf[13] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + BUF);
-       ipi_mailbox_buf[14] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + BUF);
-       ipi_mailbox_buf[15] = (void *)
-               (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + BUF);
-}
-
-/*
- * Simple enough, just poke the appropriate ipi register
- */
-static void loongson3_send_ipi_single(int cpu, unsigned int action)
-{
-       ipi_write_action(cpu_logical_map(cpu), (u32)action);
-}
-
-static void
-loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action)
-{
-       unsigned int i;
-
-       for_each_cpu(i, mask)
-               ipi_write_action(cpu_logical_map(i), (u32)action);
-}
-
-#define IPI_IRQ_OFFSET 6
-
-void loongson3_send_irq_by_ipi(int cpu, int irqs)
-{
-       ipi_write_action(cpu_logical_map(cpu), irqs << IPI_IRQ_OFFSET);
-}
-
-void loongson3_ipi_interrupt(struct pt_regs *regs)
-{
-       int i, cpu = smp_processor_id();
-       unsigned int action, c0count, irqs;
-
-       action = ipi_read_clear(cpu);
-       irqs = action >> IPI_IRQ_OFFSET;
-
-       if (action & SMP_RESCHEDULE_YOURSELF)
-               scheduler_ipi();
-
-       if (action & SMP_CALL_FUNCTION) {
-               irq_enter();
-               generic_smp_call_function_interrupt();
-               irq_exit();
-       }
-
-       if (action & SMP_ASK_C0COUNT) {
-               BUG_ON(cpu != 0);
-               c0count = read_c0_count();
-               c0count = c0count ? c0count : 1;
-               for (i = 1; i < nr_cpu_ids; i++)
-                       core0_c0count[i] = c0count;
-               __wbflush(); /* Let others see the result ASAP */
-       }
-
-       if (irqs) {
-               int irq;
-               while ((irq = ffs(irqs))) {
-                       do_IRQ(irq-1);
-                       irqs &= ~(1<<(irq-1));
-               }
-       }
-}
-
-#define MAX_LOOPS 800
-/*
- * SMP init and finish on secondary CPUs
- */
-static void loongson3_init_secondary(void)
-{
-       int i;
-       uint32_t initcount;
-       unsigned int cpu = smp_processor_id();
-       unsigned int imask = STATUSF_IP7 | STATUSF_IP6 |
-                            STATUSF_IP3 | STATUSF_IP2;
-
-       /* Set interrupt mask, but don't enable */
-       change_c0_status(ST0_IM, imask);
-
-       for (i = 0; i < num_possible_cpus(); i++)
-               loongson3_ipi_write32(0xffffffff, ipi_en0_regs[cpu_logical_map(i)]);
-
-       per_cpu(cpu_state, cpu) = CPU_ONLINE;
-       cpu_set_core(&cpu_data[cpu],
-                    cpu_logical_map(cpu) % loongson_sysconf.cores_per_package);
-       cpu_data[cpu].package =
-               cpu_logical_map(cpu) / loongson_sysconf.cores_per_package;
-
-       i = 0;
-       core0_c0count[cpu] = 0;
-       loongson3_send_ipi_single(0, SMP_ASK_C0COUNT);
-       while (!core0_c0count[cpu]) {
-               i++;
-               cpu_relax();
-       }
-
-       if (i > MAX_LOOPS)
-               i = MAX_LOOPS;
-       if (cpu_data[cpu].package)
-               initcount = core0_c0count[cpu] + i;
-       else /* Local access is faster for loops */
-               initcount = core0_c0count[cpu] + i/2;
-
-       write_c0_count(initcount);
-}
-
-static void loongson3_smp_finish(void)
-{
-       int cpu = smp_processor_id();
-
-       write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ);
-       local_irq_enable();
-       loongson3_ipi_write64(0,
-                       ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x0);
-       pr_info("CPU#%d finished, CP0_ST=%x\n",
-                       smp_processor_id(), read_c0_status());
-}
-
-static void __init loongson3_smp_setup(void)
-{
-       int i = 0, num = 0; /* i: physical id, num: logical id */
-
-       init_cpu_possible(cpu_none_mask);
-
-       /* For unified kernel, NR_CPUS is the maximum possible value,
-        * loongson_sysconf.nr_cpus is the really present value */
-       while (i < loongson_sysconf.nr_cpus) {
-               if (loongson_sysconf.reserved_cpus_mask & (1<<i)) {
-                       /* Reserved physical CPU cores */
-                       __cpu_number_map[i] = -1;
-               } else {
-                       __cpu_number_map[i] = num;
-                       __cpu_logical_map[num] = i;
-                       set_cpu_possible(num, true);
-                       num++;
-               }
-               i++;
-       }
-       pr_info("Detected %i available CPU(s)\n", num);
-
-       while (num < loongson_sysconf.nr_cpus) {
-               __cpu_logical_map[num] = -1;
-               num++;
-       }
-
-       csr_ipi_probe();
-       ipi_set0_regs_init();
-       ipi_clear0_regs_init();
-       ipi_status0_regs_init();
-       ipi_en0_regs_init();
-       ipi_mailbox_buf_init();
-       cpu_set_core(&cpu_data[0],
-                    cpu_logical_map(0) % loongson_sysconf.cores_per_package);
-       cpu_data[0].package = cpu_logical_map(0) / loongson_sysconf.cores_per_package;
-}
-
-static void __init loongson3_prepare_cpus(unsigned int max_cpus)
-{
-       init_cpu_present(cpu_possible_mask);
-       per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
-}
-
-/*
- * Setup the PC, SP, and GP of a secondary processor and start it runing!
- */
-static int loongson3_boot_secondary(int cpu, struct task_struct *idle)
-{
-       unsigned long startargs[4];
-
-       pr_info("Booting CPU#%d...\n", cpu);
-
-       /* startargs[] are initial PC, SP and GP for secondary CPU */
-       startargs[0] = (unsigned long)&smp_bootstrap;
-       startargs[1] = (unsigned long)__KSTK_TOS(idle);
-       startargs[2] = (unsigned long)task_thread_info(idle);
-       startargs[3] = 0;
-
-       pr_debug("CPU#%d, func_pc=%lx, sp=%lx, gp=%lx\n",
-                       cpu, startargs[0], startargs[1], startargs[2]);
-
-       loongson3_ipi_write64(startargs[3],
-                       ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x18);
-       loongson3_ipi_write64(startargs[2],
-                       ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x10);
-       loongson3_ipi_write64(startargs[1],
-                       ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x8);
-       loongson3_ipi_write64(startargs[0],
-                       ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x0);
-       return 0;
-}
-
-#ifdef CONFIG_HOTPLUG_CPU
-
-static int loongson3_cpu_disable(void)
-{
-       unsigned long flags;
-       unsigned int cpu = smp_processor_id();
-
-       if (cpu == 0)
-               return -EBUSY;
-
-       set_cpu_online(cpu, false);
-       calculate_cpu_foreign_map();
-       local_irq_save(flags);
-       fixup_irqs();
-       local_irq_restore(flags);
-       local_flush_tlb_all();
-
-       return 0;
-}
-
-
-static void loongson3_cpu_die(unsigned int cpu)
-{
-       while (per_cpu(cpu_state, cpu) != CPU_DEAD)
-               cpu_relax();
-
-       mb();
-}
-
-/* To shutdown a core in Loongson 3, the target core should go to CKSEG1 and
- * flush all L1 entries at first. Then, another core (usually Core 0) can
- * safely disable the clock of the target core. loongson3_play_dead() is
- * called via CKSEG1 (uncached and unmmaped) */
-static void loongson3_type1_play_dead(int *state_addr)
-{
-       register int val;
-       register long cpuid, core, node, count;
-       register void *addr, *base, *initfunc;
-
-       __asm__ __volatile__(
-               "   .set push                     \n"
-               "   .set noreorder                \n"
-               "   li %[addr], 0x80000000        \n" /* KSEG0 */
-               "1: cache 0, 0(%[addr])           \n" /* flush L1 ICache */
-               "   cache 0, 1(%[addr])           \n"
-               "   cache 0, 2(%[addr])           \n"
-               "   cache 0, 3(%[addr])           \n"
-               "   cache 1, 0(%[addr])           \n" /* flush L1 DCache */
-               "   cache 1, 1(%[addr])           \n"
-               "   cache 1, 2(%[addr])           \n"
-               "   cache 1, 3(%[addr])           \n"
-               "   addiu %[sets], %[sets], -1    \n"
-               "   bnez  %[sets], 1b             \n"
-               "   addiu %[addr], %[addr], 0x20  \n"
-               "   li    %[val], 0x7             \n" /* *state_addr = CPU_DEAD; */
-               "   sw    %[val], (%[state_addr]) \n"
-               "   sync                          \n"
-               "   cache 21, (%[state_addr])     \n" /* flush entry of *state_addr */
-               "   .set pop                      \n"
-               : [addr] "=&r" (addr), [val] "=&r" (val)
-               : [state_addr] "r" (state_addr),
-                 [sets] "r" (cpu_data[smp_processor_id()].dcache.sets));
-
-       __asm__ __volatile__(
-               "   .set push                         \n"
-               "   .set noreorder                    \n"
-               "   .set mips64                       \n"
-               "   mfc0  %[cpuid], $15, 1            \n"
-               "   andi  %[cpuid], 0x3ff             \n"
-               "   dli   %[base], 0x900000003ff01000 \n"
-               "   andi  %[core], %[cpuid], 0x3      \n"
-               "   sll   %[core], 8                  \n" /* get core id */
-               "   or    %[base], %[base], %[core]   \n"
-               "   andi  %[node], %[cpuid], 0xc      \n"
-               "   dsll  %[node], 42                 \n" /* get node id */
-               "   or    %[base], %[base], %[node]   \n"
-               "1: li    %[count], 0x100             \n" /* wait for init loop */
-               "2: bnez  %[count], 2b                \n" /* limit mailbox access */
-               "   addiu %[count], -1                \n"
-               "   ld    %[initfunc], 0x20(%[base])  \n" /* get PC via mailbox */
-               "   beqz  %[initfunc], 1b             \n"
-               "   nop                               \n"
-               "   ld    $sp, 0x28(%[base])          \n" /* get SP via mailbox */
-               "   ld    $gp, 0x30(%[base])          \n" /* get GP via mailbox */
-               "   ld    $a1, 0x38(%[base])          \n"
-               "   jr    %[initfunc]                 \n" /* jump to initial PC */
-               "   nop                               \n"
-               "   .set pop                          \n"
-               : [core] "=&r" (core), [node] "=&r" (node),
-                 [base] "=&r" (base), [cpuid] "=&r" (cpuid),
-                 [count] "=&r" (count), [initfunc] "=&r" (initfunc)
-               : /* No Input */
-               : "a1");
-}
-
-static void loongson3_type2_play_dead(int *state_addr)
-{
-       register int val;
-       register long cpuid, core, node, count;
-       register void *addr, *base, *initfunc;
-
-       __asm__ __volatile__(
-               "   .set push                     \n"
-               "   .set noreorder                \n"
-               "   li %[addr], 0x80000000        \n" /* KSEG0 */
-               "1: cache 0, 0(%[addr])           \n" /* flush L1 ICache */
-               "   cache 0, 1(%[addr])           \n"
-               "   cache 0, 2(%[addr])           \n"
-               "   cache 0, 3(%[addr])           \n"
-               "   cache 1, 0(%[addr])           \n" /* flush L1 DCache */
-               "   cache 1, 1(%[addr])           \n"
-               "   cache 1, 2(%[addr])           \n"
-               "   cache 1, 3(%[addr])           \n"
-               "   addiu %[sets], %[sets], -1    \n"
-               "   bnez  %[sets], 1b             \n"
-               "   addiu %[addr], %[addr], 0x20  \n"
-               "   li    %[val], 0x7             \n" /* *state_addr = CPU_DEAD; */
-               "   sw    %[val], (%[state_addr]) \n"
-               "   sync                          \n"
-               "   cache 21, (%[state_addr])     \n" /* flush entry of *state_addr */
-               "   .set pop                      \n"
-               : [addr] "=&r" (addr), [val] "=&r" (val)
-               : [state_addr] "r" (state_addr),
-                 [sets] "r" (cpu_data[smp_processor_id()].dcache.sets));
-
-       __asm__ __volatile__(
-               "   .set push                         \n"
-               "   .set noreorder                    \n"
-               "   .set mips64                       \n"
-               "   mfc0  %[cpuid], $15, 1            \n"
-               "   andi  %[cpuid], 0x3ff             \n"
-               "   dli   %[base], 0x900000003ff01000 \n"
-               "   andi  %[core], %[cpuid], 0x3      \n"
-               "   sll   %[core], 8                  \n" /* get core id */
-               "   or    %[base], %[base], %[core]   \n"
-               "   andi  %[node], %[cpuid], 0xc      \n"
-               "   dsll  %[node], 42                 \n" /* get node id */
-               "   or    %[base], %[base], %[node]   \n"
-               "   dsrl  %[node], 30                 \n" /* 15:14 */
-               "   or    %[base], %[base], %[node]   \n"
-               "1: li    %[count], 0x100             \n" /* wait for init loop */
-               "2: bnez  %[count], 2b                \n" /* limit mailbox access */
-               "   addiu %[count], -1                \n"
-               "   ld    %[initfunc], 0x20(%[base])  \n" /* get PC via mailbox */
-               "   beqz  %[initfunc], 1b             \n"
-               "   nop                               \n"
-               "   ld    $sp, 0x28(%[base])          \n" /* get SP via mailbox */
-               "   ld    $gp, 0x30(%[base])          \n" /* get GP via mailbox */
-               "   ld    $a1, 0x38(%[base])          \n"
-               "   jr    %[initfunc]                 \n" /* jump to initial PC */
-               "   nop                               \n"
-               "   .set pop                          \n"
-               : [core] "=&r" (core), [node] "=&r" (node),
-                 [base] "=&r" (base), [cpuid] "=&r" (cpuid),
-                 [count] "=&r" (count), [initfunc] "=&r" (initfunc)
-               : /* No Input */
-               : "a1");
-}
-
-static void loongson3_type3_play_dead(int *state_addr)
-{
-       register int val;
-       register long cpuid, core, node, count;
-       register void *addr, *base, *initfunc;
-
-       __asm__ __volatile__(
-               "   .set push                     \n"
-               "   .set noreorder                \n"
-               "   li %[addr], 0x80000000        \n" /* KSEG0 */
-               "1: cache 0, 0(%[addr])           \n" /* flush L1 ICache */
-               "   cache 0, 1(%[addr])           \n"
-               "   cache 0, 2(%[addr])           \n"
-               "   cache 0, 3(%[addr])           \n"
-               "   cache 1, 0(%[addr])           \n" /* flush L1 DCache */
-               "   cache 1, 1(%[addr])           \n"
-               "   cache 1, 2(%[addr])           \n"
-               "   cache 1, 3(%[addr])           \n"
-               "   addiu %[sets], %[sets], -1    \n"
-               "   bnez  %[sets], 1b             \n"
-               "   addiu %[addr], %[addr], 0x40  \n"
-               "   li %[addr], 0x80000000        \n" /* KSEG0 */
-               "2: cache 2, 0(%[addr])           \n" /* flush L1 VCache */
-               "   cache 2, 1(%[addr])           \n"
-               "   cache 2, 2(%[addr])           \n"
-               "   cache 2, 3(%[addr])           \n"
-               "   cache 2, 4(%[addr])           \n"
-               "   cache 2, 5(%[addr])           \n"
-               "   cache 2, 6(%[addr])           \n"
-               "   cache 2, 7(%[addr])           \n"
-               "   cache 2, 8(%[addr])           \n"
-               "   cache 2, 9(%[addr])           \n"
-               "   cache 2, 10(%[addr])          \n"
-               "   cache 2, 11(%[addr])          \n"
-               "   cache 2, 12(%[addr])          \n"
-               "   cache 2, 13(%[addr])          \n"
-               "   cache 2, 14(%[addr])          \n"
-               "   cache 2, 15(%[addr])          \n"
-               "   addiu %[vsets], %[vsets], -1  \n"
-               "   bnez  %[vsets], 2b            \n"
-               "   addiu %[addr], %[addr], 0x40  \n"
-               "   li    %[val], 0x7             \n" /* *state_addr = CPU_DEAD; */
-               "   sw    %[val], (%[state_addr]) \n"
-               "   sync                          \n"
-               "   cache 21, (%[state_addr])     \n" /* flush entry of *state_addr */
-               "   .set pop                      \n"
-               : [addr] "=&r" (addr), [val] "=&r" (val)
-               : [state_addr] "r" (state_addr),
-                 [sets] "r" (cpu_data[smp_processor_id()].dcache.sets),
-                 [vsets] "r" (cpu_data[smp_processor_id()].vcache.sets));
-
-       __asm__ __volatile__(
-               "   .set push                         \n"
-               "   .set noreorder                    \n"
-               "   .set mips64                       \n"
-               "   mfc0  %[cpuid], $15, 1            \n"
-               "   andi  %[cpuid], 0x3ff             \n"
-               "   dli   %[base], 0x900000003ff01000 \n"
-               "   andi  %[core], %[cpuid], 0x3      \n"
-               "   sll   %[core], 8                  \n" /* get core id */
-               "   or    %[base], %[base], %[core]   \n"
-               "   andi  %[node], %[cpuid], 0xc      \n"
-               "   dsll  %[node], 42                 \n" /* get node id */
-               "   or    %[base], %[base], %[node]   \n"
-               "1: li    %[count], 0x100             \n" /* wait for init loop */
-               "2: bnez  %[count], 2b                \n" /* limit mailbox access */
-               "   addiu %[count], -1                \n"
-               "   ld    %[initfunc], 0x20(%[base])  \n" /* get PC via mailbox */
-               "   beqz  %[initfunc], 1b             \n"
-               "   nop                               \n"
-               "   ld    $sp, 0x28(%[base])          \n" /* get SP via mailbox */
-               "   ld    $gp, 0x30(%[base])          \n" /* get GP via mailbox */
-               "   ld    $a1, 0x38(%[base])          \n"
-               "   jr    %[initfunc]                 \n" /* jump to initial PC */
-               "   nop                               \n"
-               "   .set pop                          \n"
-               : [core] "=&r" (core), [node] "=&r" (node),
-                 [base] "=&r" (base), [cpuid] "=&r" (cpuid),
-                 [count] "=&r" (count), [initfunc] "=&r" (initfunc)
-               : /* No Input */
-               : "a1");
-}
-
-void play_dead(void)
-{
-       int prid_imp, prid_rev, *state_addr;
-       unsigned int cpu = smp_processor_id();
-       void (*play_dead_at_ckseg1)(int *);
-
-       idle_task_exit();
-
-       prid_imp = read_c0_prid() & PRID_IMP_MASK;
-       prid_rev = read_c0_prid() & PRID_REV_MASK;
-
-       if (prid_imp == PRID_IMP_LOONGSON_64G) {
-               play_dead_at_ckseg1 =
-                       (void *)CKSEG1ADDR((unsigned long)loongson3_type3_play_dead);
-               goto out;
-       }
-
-       switch (prid_rev) {
-       case PRID_REV_LOONGSON3A_R1:
-       default:
-               play_dead_at_ckseg1 =
-                       (void *)CKSEG1ADDR((unsigned long)loongson3_type1_play_dead);
-               break;
-       case PRID_REV_LOONGSON3B_R1:
-       case PRID_REV_LOONGSON3B_R2:
-               play_dead_at_ckseg1 =
-                       (void *)CKSEG1ADDR((unsigned long)loongson3_type2_play_dead);
-               break;
-       case PRID_REV_LOONGSON3A_R2_0:
-       case PRID_REV_LOONGSON3A_R2_1:
-       case PRID_REV_LOONGSON3A_R3_0:
-       case PRID_REV_LOONGSON3A_R3_1:
-               play_dead_at_ckseg1 =
-                       (void *)CKSEG1ADDR((unsigned long)loongson3_type3_play_dead);
-               break;
-       }
-
-out:
-       state_addr = &per_cpu(cpu_state, cpu);
-       mb();
-       play_dead_at_ckseg1(state_addr);
-}
-
-static int loongson3_disable_clock(unsigned int cpu)
-{
-       uint64_t core_id = cpu_core(&cpu_data[cpu]);
-       uint64_t package_id = cpu_data[cpu].package;
-
-       if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1) {
-               LOONGSON_CHIPCFG(package_id) &= ~(1 << (12 + core_id));
-       } else {
-               if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG))
-                       LOONGSON_FREQCTRL(package_id) &= ~(1 << (core_id * 4 + 3));
-       }
-       return 0;
-}
-
-static int loongson3_enable_clock(unsigned int cpu)
-{
-       uint64_t core_id = cpu_core(&cpu_data[cpu]);
-       uint64_t package_id = cpu_data[cpu].package;
-
-       if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1) {
-               LOONGSON_CHIPCFG(package_id) |= 1 << (12 + core_id);
-       } else {
-               if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG))
-                       LOONGSON_FREQCTRL(package_id) |= 1 << (core_id * 4 + 3);
-       }
-       return 0;
-}
-
-static int register_loongson3_notifier(void)
-{
-       return cpuhp_setup_state_nocalls(CPUHP_MIPS_SOC_PREPARE,
-                                        "mips/loongson:prepare",
-                                        loongson3_enable_clock,
-                                        loongson3_disable_clock);
-}
-early_initcall(register_loongson3_notifier);
-
-#endif
-
-const struct plat_smp_ops loongson3_smp_ops = {
-       .send_ipi_single = loongson3_send_ipi_single,
-       .send_ipi_mask = loongson3_send_ipi_mask,
-       .init_secondary = loongson3_init_secondary,
-       .smp_finish = loongson3_smp_finish,
-       .boot_secondary = loongson3_boot_secondary,
-       .smp_setup = loongson3_smp_setup,
-       .prepare_cpus = loongson3_prepare_cpus,
-#ifdef CONFIG_HOTPLUG_CPU
-       .cpu_disable = loongson3_cpu_disable,
-       .cpu_die = loongson3_cpu_die,
-#endif
-#ifdef CONFIG_KEXEC
-       .kexec_nonboot_cpu = kexec_nonboot_cpu_jump,
-#endif
-};
diff --git a/arch/mips/loongson64/loongson-3/smp.h b/arch/mips/loongson64/loongson-3/smp.h
deleted file mode 100644 (file)
index 957bde8..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __LOONGSON_SMP_H_
-#define __LOONGSON_SMP_H_
-
-/* for Loongson-3 smp support */
-extern unsigned long long smp_group[4];
-
-/* 4 groups(nodes) in maximum in numa case */
-#define SMP_CORE_GROUP0_BASE   (smp_group[0])
-#define SMP_CORE_GROUP1_BASE   (smp_group[1])
-#define SMP_CORE_GROUP2_BASE   (smp_group[2])
-#define SMP_CORE_GROUP3_BASE   (smp_group[3])
-
-/* 4 cores in each group(node) */
-#define SMP_CORE0_OFFSET  0x000
-#define SMP_CORE1_OFFSET  0x100
-#define SMP_CORE2_OFFSET  0x200
-#define SMP_CORE3_OFFSET  0x300
-
-/* ipi registers offsets */
-#define STATUS0  0x00
-#define EN0      0x04
-#define SET0     0x08
-#define CLEAR0   0x0c
-#define STATUS1  0x10
-#define MASK1    0x14
-#define SET1     0x18
-#define CLEAR1   0x1c
-#define BUF      0x20
-
-#endif
diff --git a/arch/mips/loongson64/numa.c b/arch/mips/loongson64/numa.c
new file mode 100644 (file)
index 0000000..ef94a22
--- /dev/null
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2010 Loongson Inc. & Lemote Inc. &
+ *                    Institute of Computing Technology
+ * Author:  Xiang Gao, gaoxiang@ict.ac.cn
+ *          Huacai Chen, chenhc@lemote.com
+ *          Xiaofu Meng, Shuangshuang Zhang
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <linux/export.h>
+#include <linux/nodemask.h>
+#include <linux/swap.h>
+#include <linux/memblock.h>
+#include <linux/pfn.h>
+#include <linux/highmem.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/sections.h>
+#include <linux/irq.h>
+#include <asm/bootinfo.h>
+#include <asm/mc146818-time.h>
+#include <asm/time.h>
+#include <asm/wbflush.h>
+#include <boot_param.h>
+
+static struct pglist_data prealloc__node_data[MAX_NUMNODES];
+unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES];
+EXPORT_SYMBOL(__node_distances);
+struct pglist_data *__node_data[MAX_NUMNODES];
+EXPORT_SYMBOL(__node_data);
+
+cpumask_t __node_cpumask[MAX_NUMNODES];
+EXPORT_SYMBOL(__node_cpumask);
+
+static void enable_lpa(void)
+{
+       unsigned long value;
+
+       value = __read_32bit_c0_register($16, 3);
+       value |= 0x00000080;
+       __write_32bit_c0_register($16, 3, value);
+       value = __read_32bit_c0_register($16, 3);
+       pr_info("CP0_Config3: CP0 16.3 (0x%lx)\n", value);
+
+       value = __read_32bit_c0_register($5, 1);
+       value |= 0x20000000;
+       __write_32bit_c0_register($5, 1, value);
+       value = __read_32bit_c0_register($5, 1);
+       pr_info("CP0_PageGrain: CP0 5.1 (0x%lx)\n", value);
+}
+
+static void cpu_node_probe(void)
+{
+       int i;
+
+       nodes_clear(node_possible_map);
+       nodes_clear(node_online_map);
+       for (i = 0; i < loongson_sysconf.nr_nodes; i++) {
+               node_set_state(num_online_nodes(), N_POSSIBLE);
+               node_set_online(num_online_nodes());
+       }
+
+       pr_info("NUMA: Discovered %d cpus on %d nodes\n",
+               loongson_sysconf.nr_cpus, num_online_nodes());
+}
+
+static int __init compute_node_distance(int row, int col)
+{
+       int package_row = row * loongson_sysconf.cores_per_node /
+                               loongson_sysconf.cores_per_package;
+       int package_col = col * loongson_sysconf.cores_per_node /
+                               loongson_sysconf.cores_per_package;
+
+       if (col == row)
+               return 0;
+       else if (package_row == package_col)
+               return 40;
+       else
+               return 100;
+}
+
+static void __init init_topology_matrix(void)
+{
+       int row, col;
+
+       for (row = 0; row < MAX_NUMNODES; row++)
+               for (col = 0; col < MAX_NUMNODES; col++)
+                       __node_distances[row][col] = -1;
+
+       for_each_online_node(row) {
+               for_each_online_node(col) {
+                       __node_distances[row][col] =
+                               compute_node_distance(row, col);
+               }
+       }
+}
+
+static unsigned long nid_to_addroffset(unsigned int nid)
+{
+       unsigned long result;
+       switch (nid) {
+       case 0:
+       default:
+               result = NODE0_ADDRSPACE_OFFSET;
+               break;
+       case 1:
+               result = NODE1_ADDRSPACE_OFFSET;
+               break;
+       case 2:
+               result = NODE2_ADDRSPACE_OFFSET;
+               break;
+       case 3:
+               result = NODE3_ADDRSPACE_OFFSET;
+               break;
+       }
+       return result;
+}
+
+static void __init szmem(unsigned int node)
+{
+       u32 i, mem_type;
+       static unsigned long num_physpages = 0;
+       u64 node_id, node_psize, start_pfn, end_pfn, mem_start, mem_size;
+
+       /* Parse memory information and activate */
+       for (i = 0; i < loongson_memmap->nr_map; i++) {
+               node_id = loongson_memmap->map[i].node_id;
+               if (node_id != node)
+                       continue;
+
+               mem_type = loongson_memmap->map[i].mem_type;
+               mem_size = loongson_memmap->map[i].mem_size;
+               mem_start = loongson_memmap->map[i].mem_start;
+
+               switch (mem_type) {
+               case SYSTEM_RAM_LOW:
+                       start_pfn = ((node_id << 44) + mem_start) >> PAGE_SHIFT;
+                       node_psize = (mem_size << 20) >> PAGE_SHIFT;
+                       end_pfn  = start_pfn + node_psize;
+                       num_physpages += node_psize;
+                       pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
+                               (u32)node_id, mem_type, mem_start, mem_size);
+                       pr_info("       start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n",
+                               start_pfn, end_pfn, num_physpages);
+                       memblock_add_node(PFN_PHYS(start_pfn),
+                               PFN_PHYS(end_pfn - start_pfn), node);
+                       break;
+               case SYSTEM_RAM_HIGH:
+                       start_pfn = ((node_id << 44) + mem_start) >> PAGE_SHIFT;
+                       node_psize = (mem_size << 20) >> PAGE_SHIFT;
+                       end_pfn  = start_pfn + node_psize;
+                       num_physpages += node_psize;
+                       pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
+                               (u32)node_id, mem_type, mem_start, mem_size);
+                       pr_info("       start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n",
+                               start_pfn, end_pfn, num_physpages);
+                       memblock_add_node(PFN_PHYS(start_pfn),
+                               PFN_PHYS(end_pfn - start_pfn), node);
+                       break;
+               case SYSTEM_RAM_RESERVED:
+                       pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
+                               (u32)node_id, mem_type, mem_start, mem_size);
+                       memblock_reserve(((node_id << 44) + mem_start),
+                               mem_size << 20);
+                       break;
+               }
+       }
+}
+
+static void __init node_mem_init(unsigned int node)
+{
+       unsigned long node_addrspace_offset;
+       unsigned long start_pfn, end_pfn;
+
+       node_addrspace_offset = nid_to_addroffset(node);
+       pr_info("Node%d's addrspace_offset is 0x%lx\n",
+                       node, node_addrspace_offset);
+
+       get_pfn_range_for_nid(node, &start_pfn, &end_pfn);
+       pr_info("Node%d: start_pfn=0x%lx, end_pfn=0x%lx\n",
+               node, start_pfn, end_pfn);
+
+       __node_data[node] = prealloc__node_data + node;
+
+       NODE_DATA(node)->node_start_pfn = start_pfn;
+       NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn;
+
+       if (node == 0) {
+               /* kernel end address */
+               unsigned long kernel_end_pfn = PFN_UP(__pa_symbol(&_end));
+
+               /* used by finalize_initrd() */
+               max_low_pfn = end_pfn;
+
+               /* Reserve the kernel text/data/bss */
+               memblock_reserve(start_pfn << PAGE_SHIFT,
+                                ((kernel_end_pfn - start_pfn) << PAGE_SHIFT));
+
+               /* Reserve 0xfe000000~0xffffffff for RS780E integrated GPU */
+               if (node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT))
+                       memblock_reserve((node_addrspace_offset | 0xfe000000),
+                                        32 << 20);
+       }
+}
+
+static __init void prom_meminit(void)
+{
+       unsigned int node, cpu, active_cpu = 0;
+
+       cpu_node_probe();
+       init_topology_matrix();
+
+       for (node = 0; node < loongson_sysconf.nr_nodes; node++) {
+               if (node_online(node)) {
+                       szmem(node);
+                       node_mem_init(node);
+                       cpumask_clear(&__node_cpumask[node]);
+               }
+       }
+       memblocks_present();
+       max_low_pfn = PHYS_PFN(memblock_end_of_DRAM());
+
+       for (cpu = 0; cpu < loongson_sysconf.nr_cpus; cpu++) {
+               node = cpu / loongson_sysconf.cores_per_node;
+               if (node >= num_online_nodes())
+                       node = 0;
+
+               if (loongson_sysconf.reserved_cpus_mask & (1<<cpu))
+                       continue;
+
+               cpumask_set_cpu(active_cpu, &__node_cpumask[node]);
+               pr_info("NUMA: set cpumask cpu %d on node %d\n", active_cpu, node);
+
+               active_cpu++;
+       }
+}
+
+void __init paging_init(void)
+{
+       unsigned long zones_size[MAX_NR_ZONES] = {0, };
+
+       pagetable_init();
+#ifdef CONFIG_ZONE_DMA32
+       zones_size[ZONE_DMA32] = MAX_DMA32_PFN;
+#endif
+       zones_size[ZONE_NORMAL] = max_low_pfn;
+       free_area_init_nodes(zones_size);
+}
+
+void __init mem_init(void)
+{
+       high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT);
+       memblock_free_all();
+       setup_zero_pages();     /* This comes from node 0 */
+       mem_init_print_info(NULL);
+}
+
+/* All PCI device belongs to logical Node-0 */
+int pcibus_to_node(struct pci_bus *bus)
+{
+       return 0;
+}
+EXPORT_SYMBOL(pcibus_to_node);
+
+void __init prom_init_numa_memory(void)
+{
+       enable_lpa();
+       prom_meminit();
+}
+EXPORT_SYMBOL(prom_init_numa_memory);
diff --git a/arch/mips/loongson64/pci.c b/arch/mips/loongson64/pci.c
new file mode 100644 (file)
index 0000000..7bbe238
--- /dev/null
@@ -0,0 +1,94 @@
+// 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>
+#include <boot_param.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;
+       loongson_pci_mem_resource.start = loongson_sysconf.pci_mem_start_addr;
+       loongson_pci_mem_resource.end = loongson_sysconf.pci_mem_end_addr;
+
+       register_pci_controller(&loongson_pci_controller);
+
+       sbx00_acpi_init();
+
+       return 0;
+}
+
+arch_initcall(pcibios_init);
diff --git a/arch/mips/loongson64/platform.c b/arch/mips/loongson64/platform.c
new file mode 100644 (file)
index 0000000..13f3404
--- /dev/null
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *         Xiang Yu, xiangy@lemote.com
+ *         Chen Huacai, chenhc@lemote.com
+ */
+
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <asm/bootinfo.h>
+#include <boot_param.h>
+#include <loongson_hwmon.h>
+#include <workarounds.h>
+
+static int __init loongson3_platform_init(void)
+{
+       int i;
+       struct platform_device *pdev;
+
+       if (loongson_sysconf.ecname[0] != '\0')
+               platform_device_register_simple(loongson_sysconf.ecname, -1, NULL, 0);
+
+       for (i = 0; i < loongson_sysconf.nr_sensors; i++) {
+               if (loongson_sysconf.sensors[i].type > SENSOR_FAN)
+                       continue;
+
+               pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
+               pdev->name = loongson_sysconf.sensors[i].name;
+               pdev->id = loongson_sysconf.sensors[i].id;
+               pdev->dev.platform_data = &loongson_sysconf.sensors[i];
+               platform_device_register(pdev);
+       }
+
+       return 0;
+}
+
+arch_initcall(loongson3_platform_init);
diff --git a/arch/mips/loongson64/pm.c b/arch/mips/loongson64/pm.c
new file mode 100644 (file)
index 0000000..7c8556f
--- /dev/null
@@ -0,0 +1,104 @@
+// 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)
+{
+}
+
+void __weak mach_suspend(void)
+{
+}
+
+void __weak mach_resume(void)
+{
+}
+
+static int loongson_pm_enter(suspend_state_t state)
+{
+       mach_suspend();
+
+       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/loongson64/reset.c b/arch/mips/loongson64/reset.c
new file mode 100644 (file)
index 0000000..88b3bd5
--- /dev/null
@@ -0,0 +1,64 @@
+// 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>
+#include <boot_param.h>
+
+static inline void loongson_reboot(void)
+{
+       ((void (*)(void))ioremap_nocache(LOONGSON_BOOT_BASE, 4)) ();
+}
+
+static void loongson_restart(char *command)
+{
+
+       void (*fw_restart)(void) = (void *)loongson_sysconf.restart_addr;
+
+       fw_restart();
+       while (1) {
+               if (cpu_wait)
+                       cpu_wait();
+       }
+}
+
+static void loongson_poweroff(void)
+{
+       void (*fw_poweroff)(void) = (void *)loongson_sysconf.poweroff_addr;
+
+       fw_poweroff();
+       while (1) {
+               if (cpu_wait)
+                       cpu_wait();
+       }
+}
+
+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/loongson64/rtc.c b/arch/mips/loongson64/rtc.c
new file mode 100644 (file)
index 0000000..8d7628c
--- /dev/null
@@ -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/loongson64/setup.c b/arch/mips/loongson64/setup.c
new file mode 100644 (file)
index 0000000..4fd27f4
--- /dev/null
@@ -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/loongson64/smp.c b/arch/mips/loongson64/smp.c
new file mode 100644 (file)
index 0000000..de8e074
--- /dev/null
@@ -0,0 +1,813 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2010, 2011, 2012, Lemote, Inc.
+ * Author: Chen Huacai, chenhc@lemote.com
+ */
+
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/sched.h>
+#include <linux/sched/hotplug.h>
+#include <linux/sched/task_stack.h>
+#include <linux/smp.h>
+#include <linux/cpufreq.h>
+#include <linux/kexec.h>
+#include <asm/processor.h>
+#include <asm/time.h>
+#include <asm/clock.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+#include <loongson.h>
+#include <loongson_regs.h>
+#include <workarounds.h>
+
+#include "smp.h"
+
+DEFINE_PER_CPU(int, cpu_state);
+
+static void *ipi_set0_regs[16];
+static void *ipi_clear0_regs[16];
+static void *ipi_status0_regs[16];
+static void *ipi_en0_regs[16];
+static void *ipi_mailbox_buf[16];
+static uint32_t core0_c0count[NR_CPUS];
+
+/* read a 32bit value from ipi register */
+#define loongson3_ipi_read32(addr) readl(addr)
+/* read a 64bit value from ipi register */
+#define loongson3_ipi_read64(addr) readq(addr)
+/* write a 32bit value to ipi register */
+#define loongson3_ipi_write32(action, addr)    \
+       do {                                    \
+               writel(action, addr);           \
+               __wbflush();                    \
+       } while (0)
+/* write a 64bit value to ipi register */
+#define loongson3_ipi_write64(action, addr)    \
+       do {                                    \
+               writeq(action, addr);           \
+               __wbflush();                    \
+       } while (0)
+
+u32 (*ipi_read_clear)(int cpu);
+void (*ipi_write_action)(int cpu, u32 action);
+
+static u32 csr_ipi_read_clear(int cpu)
+{
+       u32 action;
+
+       /* Load the ipi register to figure out what we're supposed to do */
+       action = csr_readl(LOONGSON_CSR_IPI_STATUS);
+       /* Clear the ipi register to clear the interrupt */
+       csr_writel(action, LOONGSON_CSR_IPI_CLEAR);
+
+       return action;
+}
+
+static void csr_ipi_write_action(int cpu, u32 action)
+{
+       unsigned int irq = 0;
+
+       while ((irq = ffs(action))) {
+               uint32_t val = CSR_IPI_SEND_BLOCK;
+               val |= (irq - 1);
+               val |= (cpu << CSR_IPI_SEND_CPU_SHIFT);
+               csr_writel(val, LOONGSON_CSR_IPI_SEND);
+               action &= ~BIT(irq - 1);
+       }
+}
+
+static u32 legacy_ipi_read_clear(int cpu)
+{
+       u32 action;
+
+       /* Load the ipi register to figure out what we're supposed to do */
+       action = loongson3_ipi_read32(ipi_status0_regs[cpu_logical_map(cpu)]);
+       /* Clear the ipi register to clear the interrupt */
+       loongson3_ipi_write32(action, ipi_clear0_regs[cpu_logical_map(cpu)]);
+
+       return action;
+}
+
+static void legacy_ipi_write_action(int cpu, u32 action)
+{
+       loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu]);
+}
+
+static void csr_ipi_probe(void)
+{
+       if (cpu_has_csr() && csr_readl(LOONGSON_CSR_FEATURES) & LOONGSON_CSRF_IPI) {
+               ipi_read_clear = csr_ipi_read_clear;
+               ipi_write_action = csr_ipi_write_action;
+       } else {
+               ipi_read_clear = legacy_ipi_read_clear;
+               ipi_write_action = legacy_ipi_write_action;
+       }
+}
+
+static void ipi_set0_regs_init(void)
+{
+       ipi_set0_regs[0] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + SET0);
+       ipi_set0_regs[1] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + SET0);
+       ipi_set0_regs[2] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + SET0);
+       ipi_set0_regs[3] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + SET0);
+       ipi_set0_regs[4] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + SET0);
+       ipi_set0_regs[5] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + SET0);
+       ipi_set0_regs[6] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + SET0);
+       ipi_set0_regs[7] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + SET0);
+       ipi_set0_regs[8] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + SET0);
+       ipi_set0_regs[9] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + SET0);
+       ipi_set0_regs[10] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + SET0);
+       ipi_set0_regs[11] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + SET0);
+       ipi_set0_regs[12] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + SET0);
+       ipi_set0_regs[13] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + SET0);
+       ipi_set0_regs[14] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + SET0);
+       ipi_set0_regs[15] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + SET0);
+}
+
+static void ipi_clear0_regs_init(void)
+{
+       ipi_clear0_regs[0] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + CLEAR0);
+       ipi_clear0_regs[1] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + CLEAR0);
+       ipi_clear0_regs[2] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + CLEAR0);
+       ipi_clear0_regs[3] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + CLEAR0);
+       ipi_clear0_regs[4] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + CLEAR0);
+       ipi_clear0_regs[5] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + CLEAR0);
+       ipi_clear0_regs[6] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + CLEAR0);
+       ipi_clear0_regs[7] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + CLEAR0);
+       ipi_clear0_regs[8] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + CLEAR0);
+       ipi_clear0_regs[9] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + CLEAR0);
+       ipi_clear0_regs[10] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + CLEAR0);
+       ipi_clear0_regs[11] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + CLEAR0);
+       ipi_clear0_regs[12] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + CLEAR0);
+       ipi_clear0_regs[13] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + CLEAR0);
+       ipi_clear0_regs[14] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + CLEAR0);
+       ipi_clear0_regs[15] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + CLEAR0);
+}
+
+static void ipi_status0_regs_init(void)
+{
+       ipi_status0_regs[0] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + STATUS0);
+       ipi_status0_regs[1] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + STATUS0);
+       ipi_status0_regs[2] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + STATUS0);
+       ipi_status0_regs[3] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + STATUS0);
+       ipi_status0_regs[4] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + STATUS0);
+       ipi_status0_regs[5] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + STATUS0);
+       ipi_status0_regs[6] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + STATUS0);
+       ipi_status0_regs[7] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + STATUS0);
+       ipi_status0_regs[8] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + STATUS0);
+       ipi_status0_regs[9] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + STATUS0);
+       ipi_status0_regs[10] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + STATUS0);
+       ipi_status0_regs[11] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + STATUS0);
+       ipi_status0_regs[12] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + STATUS0);
+       ipi_status0_regs[13] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + STATUS0);
+       ipi_status0_regs[14] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + STATUS0);
+       ipi_status0_regs[15] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + STATUS0);
+}
+
+static void ipi_en0_regs_init(void)
+{
+       ipi_en0_regs[0] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + EN0);
+       ipi_en0_regs[1] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + EN0);
+       ipi_en0_regs[2] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + EN0);
+       ipi_en0_regs[3] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + EN0);
+       ipi_en0_regs[4] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + EN0);
+       ipi_en0_regs[5] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + EN0);
+       ipi_en0_regs[6] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + EN0);
+       ipi_en0_regs[7] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + EN0);
+       ipi_en0_regs[8] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + EN0);
+       ipi_en0_regs[9] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + EN0);
+       ipi_en0_regs[10] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + EN0);
+       ipi_en0_regs[11] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + EN0);
+       ipi_en0_regs[12] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + EN0);
+       ipi_en0_regs[13] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + EN0);
+       ipi_en0_regs[14] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + EN0);
+       ipi_en0_regs[15] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + EN0);
+}
+
+static void ipi_mailbox_buf_init(void)
+{
+       ipi_mailbox_buf[0] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + BUF);
+       ipi_mailbox_buf[1] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + BUF);
+       ipi_mailbox_buf[2] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + BUF);
+       ipi_mailbox_buf[3] = (void *)
+               (SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + BUF);
+       ipi_mailbox_buf[4] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + BUF);
+       ipi_mailbox_buf[5] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + BUF);
+       ipi_mailbox_buf[6] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + BUF);
+       ipi_mailbox_buf[7] = (void *)
+               (SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + BUF);
+       ipi_mailbox_buf[8] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + BUF);
+       ipi_mailbox_buf[9] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + BUF);
+       ipi_mailbox_buf[10] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + BUF);
+       ipi_mailbox_buf[11] = (void *)
+               (SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + BUF);
+       ipi_mailbox_buf[12] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + BUF);
+       ipi_mailbox_buf[13] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + BUF);
+       ipi_mailbox_buf[14] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + BUF);
+       ipi_mailbox_buf[15] = (void *)
+               (SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + BUF);
+}
+
+/*
+ * Simple enough, just poke the appropriate ipi register
+ */
+static void loongson3_send_ipi_single(int cpu, unsigned int action)
+{
+       ipi_write_action(cpu_logical_map(cpu), (u32)action);
+}
+
+static void
+loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action)
+{
+       unsigned int i;
+
+       for_each_cpu(i, mask)
+               ipi_write_action(cpu_logical_map(i), (u32)action);
+}
+
+#define IPI_IRQ_OFFSET 6
+
+void loongson3_send_irq_by_ipi(int cpu, int irqs)
+{
+       ipi_write_action(cpu_logical_map(cpu), irqs << IPI_IRQ_OFFSET);
+}
+
+void loongson3_ipi_interrupt(struct pt_regs *regs)
+{
+       int i, cpu = smp_processor_id();
+       unsigned int action, c0count, irqs;
+
+       action = ipi_read_clear(cpu);
+       irqs = action >> IPI_IRQ_OFFSET;
+
+       if (action & SMP_RESCHEDULE_YOURSELF)
+               scheduler_ipi();
+
+       if (action & SMP_CALL_FUNCTION) {
+               irq_enter();
+               generic_smp_call_function_interrupt();
+               irq_exit();
+       }
+
+       if (action & SMP_ASK_C0COUNT) {
+               BUG_ON(cpu != 0);
+               c0count = read_c0_count();
+               c0count = c0count ? c0count : 1;
+               for (i = 1; i < nr_cpu_ids; i++)
+                       core0_c0count[i] = c0count;
+               __wbflush(); /* Let others see the result ASAP */
+       }
+
+       if (irqs) {
+               int irq;
+               while ((irq = ffs(irqs))) {
+                       do_IRQ(irq-1);
+                       irqs &= ~(1<<(irq-1));
+               }
+       }
+}
+
+#define MAX_LOOPS 800
+/*
+ * SMP init and finish on secondary CPUs
+ */
+static void loongson3_init_secondary(void)
+{
+       int i;
+       uint32_t initcount;
+       unsigned int cpu = smp_processor_id();
+       unsigned int imask = STATUSF_IP7 | STATUSF_IP6 |
+                            STATUSF_IP3 | STATUSF_IP2;
+
+       /* Set interrupt mask, but don't enable */
+       change_c0_status(ST0_IM, imask);
+
+       for (i = 0; i < num_possible_cpus(); i++)
+               loongson3_ipi_write32(0xffffffff, ipi_en0_regs[cpu_logical_map(i)]);
+
+       per_cpu(cpu_state, cpu) = CPU_ONLINE;
+       cpu_set_core(&cpu_data[cpu],
+                    cpu_logical_map(cpu) % loongson_sysconf.cores_per_package);
+       cpu_data[cpu].package =
+               cpu_logical_map(cpu) / loongson_sysconf.cores_per_package;
+
+       i = 0;
+       core0_c0count[cpu] = 0;
+       loongson3_send_ipi_single(0, SMP_ASK_C0COUNT);
+       while (!core0_c0count[cpu]) {
+               i++;
+               cpu_relax();
+       }
+
+       if (i > MAX_LOOPS)
+               i = MAX_LOOPS;
+       if (cpu_data[cpu].package)
+               initcount = core0_c0count[cpu] + i;
+       else /* Local access is faster for loops */
+               initcount = core0_c0count[cpu] + i/2;
+
+       write_c0_count(initcount);
+}
+
+static void loongson3_smp_finish(void)
+{
+       int cpu = smp_processor_id();
+
+       write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ);
+       local_irq_enable();
+       loongson3_ipi_write64(0,
+                       ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x0);
+       pr_info("CPU#%d finished, CP0_ST=%x\n",
+                       smp_processor_id(), read_c0_status());
+}
+
+static void __init loongson3_smp_setup(void)
+{
+       int i = 0, num = 0; /* i: physical id, num: logical id */
+
+       init_cpu_possible(cpu_none_mask);
+
+       /* For unified kernel, NR_CPUS is the maximum possible value,
+        * loongson_sysconf.nr_cpus is the really present value */
+       while (i < loongson_sysconf.nr_cpus) {
+               if (loongson_sysconf.reserved_cpus_mask & (1<<i)) {
+                       /* Reserved physical CPU cores */
+                       __cpu_number_map[i] = -1;
+               } else {
+                       __cpu_number_map[i] = num;
+                       __cpu_logical_map[num] = i;
+                       set_cpu_possible(num, true);
+                       num++;
+               }
+               i++;
+       }
+       pr_info("Detected %i available CPU(s)\n", num);
+
+       while (num < loongson_sysconf.nr_cpus) {
+               __cpu_logical_map[num] = -1;
+               num++;
+       }
+
+       csr_ipi_probe();
+       ipi_set0_regs_init();
+       ipi_clear0_regs_init();
+       ipi_status0_regs_init();
+       ipi_en0_regs_init();
+       ipi_mailbox_buf_init();
+       cpu_set_core(&cpu_data[0],
+                    cpu_logical_map(0) % loongson_sysconf.cores_per_package);
+       cpu_data[0].package = cpu_logical_map(0) / loongson_sysconf.cores_per_package;
+}
+
+static void __init loongson3_prepare_cpus(unsigned int max_cpus)
+{
+       init_cpu_present(cpu_possible_mask);
+       per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+}
+
+/*
+ * Setup the PC, SP, and GP of a secondary processor and start it runing!
+ */
+static int loongson3_boot_secondary(int cpu, struct task_struct *idle)
+{
+       unsigned long startargs[4];
+
+       pr_info("Booting CPU#%d...\n", cpu);
+
+       /* startargs[] are initial PC, SP and GP for secondary CPU */
+       startargs[0] = (unsigned long)&smp_bootstrap;
+       startargs[1] = (unsigned long)__KSTK_TOS(idle);
+       startargs[2] = (unsigned long)task_thread_info(idle);
+       startargs[3] = 0;
+
+       pr_debug("CPU#%d, func_pc=%lx, sp=%lx, gp=%lx\n",
+                       cpu, startargs[0], startargs[1], startargs[2]);
+
+       loongson3_ipi_write64(startargs[3],
+                       ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x18);
+       loongson3_ipi_write64(startargs[2],
+                       ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x10);
+       loongson3_ipi_write64(startargs[1],
+                       ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x8);
+       loongson3_ipi_write64(startargs[0],
+                       ipi_mailbox_buf[cpu_logical_map(cpu)] + 0x0);
+       return 0;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+static int loongson3_cpu_disable(void)
+{
+       unsigned long flags;
+       unsigned int cpu = smp_processor_id();
+
+       if (cpu == 0)
+               return -EBUSY;
+
+       set_cpu_online(cpu, false);
+       calculate_cpu_foreign_map();
+       local_irq_save(flags);
+       fixup_irqs();
+       local_irq_restore(flags);
+       local_flush_tlb_all();
+
+       return 0;
+}
+
+
+static void loongson3_cpu_die(unsigned int cpu)
+{
+       while (per_cpu(cpu_state, cpu) != CPU_DEAD)
+               cpu_relax();
+
+       mb();
+}
+
+/* To shutdown a core in Loongson 3, the target core should go to CKSEG1 and
+ * flush all L1 entries at first. Then, another core (usually Core 0) can
+ * safely disable the clock of the target core. loongson3_play_dead() is
+ * called via CKSEG1 (uncached and unmmaped) */
+static void loongson3_type1_play_dead(int *state_addr)
+{
+       register int val;
+       register long cpuid, core, node, count;
+       register void *addr, *base, *initfunc;
+
+       __asm__ __volatile__(
+               "   .set push                     \n"
+               "   .set noreorder                \n"
+               "   li %[addr], 0x80000000        \n" /* KSEG0 */
+               "1: cache 0, 0(%[addr])           \n" /* flush L1 ICache */
+               "   cache 0, 1(%[addr])           \n"
+               "   cache 0, 2(%[addr])           \n"
+               "   cache 0, 3(%[addr])           \n"
+               "   cache 1, 0(%[addr])           \n" /* flush L1 DCache */
+               "   cache 1, 1(%[addr])           \n"
+               "   cache 1, 2(%[addr])           \n"
+               "   cache 1, 3(%[addr])           \n"
+               "   addiu %[sets], %[sets], -1    \n"
+               "   bnez  %[sets], 1b             \n"
+               "   addiu %[addr], %[addr], 0x20  \n"
+               "   li    %[val], 0x7             \n" /* *state_addr = CPU_DEAD; */
+               "   sw    %[val], (%[state_addr]) \n"
+               "   sync                          \n"
+               "   cache 21, (%[state_addr])     \n" /* flush entry of *state_addr */
+               "   .set pop                      \n"
+               : [addr] "=&r" (addr), [val] "=&r" (val)
+               : [state_addr] "r" (state_addr),
+                 [sets] "r" (cpu_data[smp_processor_id()].dcache.sets));
+
+       __asm__ __volatile__(
+               "   .set push                         \n"
+               "   .set noreorder                    \n"
+               "   .set mips64                       \n"
+               "   mfc0  %[cpuid], $15, 1            \n"
+               "   andi  %[cpuid], 0x3ff             \n"
+               "   dli   %[base], 0x900000003ff01000 \n"
+               "   andi  %[core], %[cpuid], 0x3      \n"
+               "   sll   %[core], 8                  \n" /* get core id */
+               "   or    %[base], %[base], %[core]   \n"
+               "   andi  %[node], %[cpuid], 0xc      \n"
+               "   dsll  %[node], 42                 \n" /* get node id */
+               "   or    %[base], %[base], %[node]   \n"
+               "1: li    %[count], 0x100             \n" /* wait for init loop */
+               "2: bnez  %[count], 2b                \n" /* limit mailbox access */
+               "   addiu %[count], -1                \n"
+               "   ld    %[initfunc], 0x20(%[base])  \n" /* get PC via mailbox */
+               "   beqz  %[initfunc], 1b             \n"
+               "   nop                               \n"
+               "   ld    $sp, 0x28(%[base])          \n" /* get SP via mailbox */
+               "   ld    $gp, 0x30(%[base])          \n" /* get GP via mailbox */
+               "   ld    $a1, 0x38(%[base])          \n"
+               "   jr    %[initfunc]                 \n" /* jump to initial PC */
+               "   nop                               \n"
+               "   .set pop                          \n"
+               : [core] "=&r" (core), [node] "=&r" (node),
+                 [base] "=&r" (base), [cpuid] "=&r" (cpuid),
+                 [count] "=&r" (count), [initfunc] "=&r" (initfunc)
+               : /* No Input */
+               : "a1");
+}
+
+static void loongson3_type2_play_dead(int *state_addr)
+{
+       register int val;
+       register long cpuid, core, node, count;
+       register void *addr, *base, *initfunc;
+
+       __asm__ __volatile__(
+               "   .set push                     \n"
+               "   .set noreorder                \n"
+               "   li %[addr], 0x80000000        \n" /* KSEG0 */
+               "1: cache 0, 0(%[addr])           \n" /* flush L1 ICache */
+               "   cache 0, 1(%[addr])           \n"
+               "   cache 0, 2(%[addr])           \n"
+               "   cache 0, 3(%[addr])           \n"
+               "   cache 1, 0(%[addr])           \n" /* flush L1 DCache */
+               "   cache 1, 1(%[addr])           \n"
+               "   cache 1, 2(%[addr])           \n"
+               "   cache 1, 3(%[addr])           \n"
+               "   addiu %[sets], %[sets], -1    \n"
+               "   bnez  %[sets], 1b             \n"
+               "   addiu %[addr], %[addr], 0x20  \n"
+               "   li    %[val], 0x7             \n" /* *state_addr = CPU_DEAD; */
+               "   sw    %[val], (%[state_addr]) \n"
+               "   sync                          \n"
+               "   cache 21, (%[state_addr])     \n" /* flush entry of *state_addr */
+               "   .set pop                      \n"
+               : [addr] "=&r" (addr), [val] "=&r" (val)
+               : [state_addr] "r" (state_addr),
+                 [sets] "r" (cpu_data[smp_processor_id()].dcache.sets));
+
+       __asm__ __volatile__(
+               "   .set push                         \n"
+               "   .set noreorder                    \n"
+               "   .set mips64                       \n"
+               "   mfc0  %[cpuid], $15, 1            \n"
+               "   andi  %[cpuid], 0x3ff             \n"
+               "   dli   %[base], 0x900000003ff01000 \n"
+               "   andi  %[core], %[cpuid], 0x3      \n"
+               "   sll   %[core], 8                  \n" /* get core id */
+               "   or    %[base], %[base], %[core]   \n"
+               "   andi  %[node], %[cpuid], 0xc      \n"
+               "   dsll  %[node], 42                 \n" /* get node id */
+               "   or    %[base], %[base], %[node]   \n"
+               "   dsrl  %[node], 30                 \n" /* 15:14 */
+               "   or    %[base], %[base], %[node]   \n"
+               "1: li    %[count], 0x100             \n" /* wait for init loop */
+               "2: bnez  %[count], 2b                \n" /* limit mailbox access */
+               "   addiu %[count], -1                \n"
+               "   ld    %[initfunc], 0x20(%[base])  \n" /* get PC via mailbox */
+               "   beqz  %[initfunc], 1b             \n"
+               "   nop                               \n"
+               "   ld    $sp, 0x28(%[base])          \n" /* get SP via mailbox */
+               "   ld    $gp, 0x30(%[base])          \n" /* get GP via mailbox */
+               "   ld    $a1, 0x38(%[base])          \n"
+               "   jr    %[initfunc]                 \n" /* jump to initial PC */
+               "   nop                               \n"
+               "   .set pop                          \n"
+               : [core] "=&r" (core), [node] "=&r" (node),
+                 [base] "=&r" (base), [cpuid] "=&r" (cpuid),
+                 [count] "=&r" (count), [initfunc] "=&r" (initfunc)
+               : /* No Input */
+               : "a1");
+}
+
+static void loongson3_type3_play_dead(int *state_addr)
+{
+       register int val;
+       register long cpuid, core, node, count;
+       register void *addr, *base, *initfunc;
+
+       __asm__ __volatile__(
+               "   .set push                     \n"
+               "   .set noreorder                \n"
+               "   li %[addr], 0x80000000        \n" /* KSEG0 */
+               "1: cache 0, 0(%[addr])           \n" /* flush L1 ICache */
+               "   cache 0, 1(%[addr])           \n"
+               "   cache 0, 2(%[addr])           \n"
+               "   cache 0, 3(%[addr])           \n"
+               "   cache 1, 0(%[addr])           \n" /* flush L1 DCache */
+               "   cache 1, 1(%[addr])           \n"
+               "   cache 1, 2(%[addr])           \n"
+               "   cache 1, 3(%[addr])           \n"
+               "   addiu %[sets], %[sets], -1    \n"
+               "   bnez  %[sets], 1b             \n"
+               "   addiu %[addr], %[addr], 0x40  \n"
+               "   li %[addr], 0x80000000        \n" /* KSEG0 */
+               "2: cache 2, 0(%[addr])           \n" /* flush L1 VCache */
+               "   cache 2, 1(%[addr])           \n"
+               "   cache 2, 2(%[addr])           \n"
+               "   cache 2, 3(%[addr])           \n"
+               "   cache 2, 4(%[addr])           \n"
+               "   cache 2, 5(%[addr])           \n"
+               "   cache 2, 6(%[addr])           \n"
+               "   cache 2, 7(%[addr])           \n"
+               "   cache 2, 8(%[addr])           \n"
+               "   cache 2, 9(%[addr])           \n"
+               "   cache 2, 10(%[addr])          \n"
+               "   cache 2, 11(%[addr])          \n"
+               "   cache 2, 12(%[addr])          \n"
+               "   cache 2, 13(%[addr])          \n"
+               "   cache 2, 14(%[addr])          \n"
+               "   cache 2, 15(%[addr])          \n"
+               "   addiu %[vsets], %[vsets], -1  \n"
+               "   bnez  %[vsets], 2b            \n"
+               "   addiu %[addr], %[addr], 0x40  \n"
+               "   li    %[val], 0x7             \n" /* *state_addr = CPU_DEAD; */
+               "   sw    %[val], (%[state_addr]) \n"
+               "   sync                          \n"
+               "   cache 21, (%[state_addr])     \n" /* flush entry of *state_addr */
+               "   .set pop                      \n"
+               : [addr] "=&r" (addr), [val] "=&r" (val)
+               : [state_addr] "r" (state_addr),
+                 [sets] "r" (cpu_data[smp_processor_id()].dcache.sets),
+                 [vsets] "r" (cpu_data[smp_processor_id()].vcache.sets));
+
+       __asm__ __volatile__(
+               "   .set push                         \n"
+               "   .set noreorder                    \n"
+               "   .set mips64                       \n"
+               "   mfc0  %[cpuid], $15, 1            \n"
+               "   andi  %[cpuid], 0x3ff             \n"
+               "   dli   %[base], 0x900000003ff01000 \n"
+               "   andi  %[core], %[cpuid], 0x3      \n"
+               "   sll   %[core], 8                  \n" /* get core id */
+               "   or    %[base], %[base], %[core]   \n"
+               "   andi  %[node], %[cpuid], 0xc      \n"
+               "   dsll  %[node], 42                 \n" /* get node id */
+               "   or    %[base], %[base], %[node]   \n"
+               "1: li    %[count], 0x100             \n" /* wait for init loop */
+               "2: bnez  %[count], 2b                \n" /* limit mailbox access */
+               "   addiu %[count], -1                \n"
+               "   ld    %[initfunc], 0x20(%[base])  \n" /* get PC via mailbox */
+               "   beqz  %[initfunc], 1b             \n"
+               "   nop                               \n"
+               "   ld    $sp, 0x28(%[base])          \n" /* get SP via mailbox */
+               "   ld    $gp, 0x30(%[base])          \n" /* get GP via mailbox */
+               "   ld    $a1, 0x38(%[base])          \n"
+               "   jr    %[initfunc]                 \n" /* jump to initial PC */
+               "   nop                               \n"
+               "   .set pop                          \n"
+               : [core] "=&r" (core), [node] "=&r" (node),
+                 [base] "=&r" (base), [cpuid] "=&r" (cpuid),
+                 [count] "=&r" (count), [initfunc] "=&r" (initfunc)
+               : /* No Input */
+               : "a1");
+}
+
+void play_dead(void)
+{
+       int prid_imp, prid_rev, *state_addr;
+       unsigned int cpu = smp_processor_id();
+       void (*play_dead_at_ckseg1)(int *);
+
+       idle_task_exit();
+
+       prid_imp = read_c0_prid() & PRID_IMP_MASK;
+       prid_rev = read_c0_prid() & PRID_REV_MASK;
+
+       if (prid_imp == PRID_IMP_LOONGSON_64G) {
+               play_dead_at_ckseg1 =
+                       (void *)CKSEG1ADDR((unsigned long)loongson3_type3_play_dead);
+               goto out;
+       }
+
+       switch (prid_rev) {
+       case PRID_REV_LOONGSON3A_R1:
+       default:
+               play_dead_at_ckseg1 =
+                       (void *)CKSEG1ADDR((unsigned long)loongson3_type1_play_dead);
+               break;
+       case PRID_REV_LOONGSON3B_R1:
+       case PRID_REV_LOONGSON3B_R2:
+               play_dead_at_ckseg1 =
+                       (void *)CKSEG1ADDR((unsigned long)loongson3_type2_play_dead);
+               break;
+       case PRID_REV_LOONGSON3A_R2_0:
+       case PRID_REV_LOONGSON3A_R2_1:
+       case PRID_REV_LOONGSON3A_R3_0:
+       case PRID_REV_LOONGSON3A_R3_1:
+               play_dead_at_ckseg1 =
+                       (void *)CKSEG1ADDR((unsigned long)loongson3_type3_play_dead);
+               break;
+       }
+
+out:
+       state_addr = &per_cpu(cpu_state, cpu);
+       mb();
+       play_dead_at_ckseg1(state_addr);
+}
+
+static int loongson3_disable_clock(unsigned int cpu)
+{
+       uint64_t core_id = cpu_core(&cpu_data[cpu]);
+       uint64_t package_id = cpu_data[cpu].package;
+
+       if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1) {
+               LOONGSON_CHIPCFG(package_id) &= ~(1 << (12 + core_id));
+       } else {
+               if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG))
+                       LOONGSON_FREQCTRL(package_id) &= ~(1 << (core_id * 4 + 3));
+       }
+       return 0;
+}
+
+static int loongson3_enable_clock(unsigned int cpu)
+{
+       uint64_t core_id = cpu_core(&cpu_data[cpu]);
+       uint64_t package_id = cpu_data[cpu].package;
+
+       if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1) {
+               LOONGSON_CHIPCFG(package_id) |= 1 << (12 + core_id);
+       } else {
+               if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG))
+                       LOONGSON_FREQCTRL(package_id) |= 1 << (core_id * 4 + 3);
+       }
+       return 0;
+}
+
+static int register_loongson3_notifier(void)
+{
+       return cpuhp_setup_state_nocalls(CPUHP_MIPS_SOC_PREPARE,
+                                        "mips/loongson:prepare",
+                                        loongson3_enable_clock,
+                                        loongson3_disable_clock);
+}
+early_initcall(register_loongson3_notifier);
+
+#endif
+
+const struct plat_smp_ops loongson3_smp_ops = {
+       .send_ipi_single = loongson3_send_ipi_single,
+       .send_ipi_mask = loongson3_send_ipi_mask,
+       .init_secondary = loongson3_init_secondary,
+       .smp_finish = loongson3_smp_finish,
+       .boot_secondary = loongson3_boot_secondary,
+       .smp_setup = loongson3_smp_setup,
+       .prepare_cpus = loongson3_prepare_cpus,
+#ifdef CONFIG_HOTPLUG_CPU
+       .cpu_disable = loongson3_cpu_disable,
+       .cpu_die = loongson3_cpu_die,
+#endif
+#ifdef CONFIG_KEXEC
+       .kexec_nonboot_cpu = kexec_nonboot_cpu_jump,
+#endif
+};
diff --git a/arch/mips/loongson64/smp.h b/arch/mips/loongson64/smp.h
new file mode 100644 (file)
index 0000000..957bde8
--- /dev/null
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LOONGSON_SMP_H_
+#define __LOONGSON_SMP_H_
+
+/* for Loongson-3 smp support */
+extern unsigned long long smp_group[4];
+
+/* 4 groups(nodes) in maximum in numa case */
+#define SMP_CORE_GROUP0_BASE   (smp_group[0])
+#define SMP_CORE_GROUP1_BASE   (smp_group[1])
+#define SMP_CORE_GROUP2_BASE   (smp_group[2])
+#define SMP_CORE_GROUP3_BASE   (smp_group[3])
+
+/* 4 cores in each group(node) */
+#define SMP_CORE0_OFFSET  0x000
+#define SMP_CORE1_OFFSET  0x100
+#define SMP_CORE2_OFFSET  0x200
+#define SMP_CORE3_OFFSET  0x300
+
+/* ipi registers offsets */
+#define STATUS0  0x00
+#define EN0      0x04
+#define SET0     0x08
+#define CLEAR0   0x0c
+#define STATUS1  0x10
+#define MASK1    0x14
+#define SET1     0x18
+#define CLEAR1   0x1c
+#define BUF      0x20
+
+#endif
diff --git a/arch/mips/loongson64/time.c b/arch/mips/loongson64/time.c
new file mode 100644 (file)
index 0000000..1245f22
--- /dev/null
@@ -0,0 +1,29 @@
+// 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>
+
+void __init plat_time_init(void)
+{
+       /* setup mips r4k timer */
+       mips_hpt_frequency = cpu_clock_freq / 2;
+
+#ifdef CONFIG_RS780_HPET
+       setup_hpet_timer();
+#endif
+}
+
+void read_persistent_clock64(struct timespec64 *ts)
+{
+       ts->tv_sec = mc146818_get_cmos_time();
+       ts->tv_nsec = 0;
+}
index d6de4cb2e31cafe13b5435606bad5aad3e9247a0..342ce10ef593dc9a8d9c7235ed391dae48d7e60b 100644 (file)
@@ -35,7 +35,7 @@ obj-$(CONFIG_LASAT)           += pci-lasat.o
 obj-$(CONFIG_MIPS_COBALT)      += fixup-cobalt.o
 obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o
 obj-$(CONFIG_LEMOTE_MACH2F)    += fixup-lemote2f.o ops-loongson2.o
-obj-$(CONFIG_LOONGSON_MACH3X)  += fixup-loongson3.o ops-loongson3.o
+obj-$(CONFIG_MACH_LOONGSON64)  += fixup-loongson3.o ops-loongson3.o
 obj-$(CONFIG_MIPS_MALTA)       += fixup-malta.o pci-malta.o
 obj-$(CONFIG_PMC_MSP7120_GW)   += fixup-pmcmsp.o ops-pmcmsp.o
 obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o
index 62ea1934fb6a676d0187a40247bea4b38a5cfd82..f4d0a86c00d079557d66e8fe71e6110d762a46fa 100644 (file)
@@ -17,8 +17,8 @@ menuconfig MIPS_PLATFORM_DEVICES
 if MIPS_PLATFORM_DEVICES
 
 config CPU_HWMON
-       tristate "Loongson CPU HWMon Driver"
-       depends on LOONGSON_MACH3X
+       tristate "Loongson-3 CPU HWMon Driver"
+       depends on CONFIG_MACH_LOONGSON64
        select HWMON
        default y
        help