summaryrefslogtreecommitdiff
path: root/arch/mips/loongson/common
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/loongson/common')
-rw-r--r--arch/mips/loongson/common/Makefile27
-rw-r--r--arch/mips/loongson/common/bonito-irq.c53
-rw-r--r--arch/mips/loongson/common/cmdline.c48
-rw-r--r--arch/mips/loongson/common/cs5536/Makefile11
-rw-r--r--arch/mips/loongson/common/cs5536/cs5536_acc.c140
-rw-r--r--arch/mips/loongson/common/cs5536/cs5536_ehci.c160
-rw-r--r--arch/mips/loongson/common/cs5536/cs5536_ide.c192
-rw-r--r--arch/mips/loongson/common/cs5536/cs5536_isa.c316
-rw-r--r--arch/mips/loongson/common/cs5536/cs5536_mfgpt.c214
-rw-r--r--arch/mips/loongson/common/cs5536/cs5536_ohci.c149
-rw-r--r--arch/mips/loongson/common/cs5536/cs5536_pci.c87
-rw-r--r--arch/mips/loongson/common/early_printk.c41
-rw-r--r--arch/mips/loongson/common/env.c79
-rw-r--r--arch/mips/loongson/common/gpio.c139
-rw-r--r--arch/mips/loongson/common/init.c39
-rw-r--r--arch/mips/loongson/common/irq.c67
-rw-r--r--arch/mips/loongson/common/machtype.c66
-rw-r--r--arch/mips/loongson/common/mem.c119
-rw-r--r--arch/mips/loongson/common/pci.c91
-rw-r--r--arch/mips/loongson/common/platform.c31
-rw-r--r--arch/mips/loongson/common/pm.c161
-rw-r--r--arch/mips/loongson/common/reset.c70
-rw-r--r--arch/mips/loongson/common/rtc.c43
-rw-r--r--arch/mips/loongson/common/serial.c76
-rw-r--r--arch/mips/loongson/common/setup.c55
-rw-r--r--arch/mips/loongson/common/time.c31
-rw-r--r--arch/mips/loongson/common/uart_base.c45
27 files changed, 2550 insertions, 0 deletions
diff --git a/arch/mips/loongson/common/Makefile b/arch/mips/loongson/common/Makefile
new file mode 100644
index 00000000..e526488d
--- /dev/null
+++ b/arch/mips/loongson/common/Makefile
@@ -0,0 +1,27 @@
+#
+# Makefile for loongson based machines.
+#
+
+obj-y += setup.o init.o cmdline.o env.o time.o reset.o irq.o \
+ pci.o bonito-irq.o mem.o machtype.o platform.o
+obj-$(CONFIG_GENERIC_GPIO) += gpio.o
+
+#
+# Serial port support
+#
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+obj-$(CONFIG_SERIAL_8250) += serial.o
+obj-$(CONFIG_LOONGSON_UART_BASE) += uart_base.o
+obj-$(CONFIG_LOONGSON_MC146818) += rtc.o
+
+#
+# Enable CS5536 Virtual Support Module(VSM) to virtulize the PCI configure
+# space
+#
+obj-$(CONFIG_CS5536) += cs5536/
+
+#
+# Suspend Support
+#
+
+obj-$(CONFIG_LOONGSON_SUSPEND) += pm.o
diff --git a/arch/mips/loongson/common/bonito-irq.c b/arch/mips/loongson/common/bonito-irq.c
new file mode 100644
index 00000000..f27d7ccc
--- /dev/null
+++ b/arch/mips/loongson/common/bonito-irq.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ * Copyright (C) 2000, 2001 Ralf Baechle (ralf@gnu.org)
+ *
+ * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/interrupt.h>
+#include <linux/compiler.h>
+
+#include <loongson.h>
+
+static inline void bonito_irq_enable(struct irq_data *d)
+{
+ LOONGSON_INTENSET = (1 << (d->irq - LOONGSON_IRQ_BASE));
+ mmiowb();
+}
+
+static inline void bonito_irq_disable(struct irq_data *d)
+{
+ LOONGSON_INTENCLR = (1 << (d->irq - LOONGSON_IRQ_BASE));
+ mmiowb();
+}
+
+static struct irq_chip bonito_irq_type = {
+ .name = "bonito_irq",
+ .irq_mask = bonito_irq_disable,
+ .irq_unmask = bonito_irq_enable,
+};
+
+static struct irqaction __maybe_unused dma_timeout_irqaction = {
+ .handler = no_action,
+ .name = "dma_timeout",
+};
+
+void bonito_irq_init(void)
+{
+ u32 i;
+
+ for (i = LOONGSON_IRQ_BASE; i < LOONGSON_IRQ_BASE + 32; i++)
+ irq_set_chip_and_handler(i, &bonito_irq_type,
+ handle_level_irq);
+
+#ifdef CONFIG_CPU_LOONGSON2E
+ setup_irq(LOONGSON_IRQ_BASE + 10, &dma_timeout_irqaction);
+#endif
+}
diff --git a/arch/mips/loongson/common/cmdline.c b/arch/mips/loongson/common/cmdline.c
new file mode 100644
index 00000000..353e1d2e
--- /dev/null
+++ b/arch/mips/loongson/common/cmdline.c
@@ -0,0 +1,48 @@
+/*
+ * 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. & Insititute of Computing Technology
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ *
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#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, " ");
+ }
+
+ prom_init_machtype();
+}
diff --git a/arch/mips/loongson/common/cs5536/Makefile b/arch/mips/loongson/common/cs5536/Makefile
new file mode 100644
index 00000000..f12e6400
--- /dev/null
+++ b/arch/mips/loongson/common/cs5536/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for CS5536 support.
+#
+
+obj-$(CONFIG_CS5536) += cs5536_pci.o cs5536_ide.o cs5536_acc.o cs5536_ohci.o \
+ cs5536_isa.o cs5536_ehci.o
+
+#
+# Enable cs5536 mfgpt Timer
+#
+obj-$(CONFIG_CS5536_MFGPT) += cs5536_mfgpt.o
diff --git a/arch/mips/loongson/common/cs5536/cs5536_acc.c b/arch/mips/loongson/common/cs5536/cs5536_acc.c
new file mode 100644
index 00000000..b3fd5eab
--- /dev/null
+++ b/arch/mips/loongson/common/cs5536/cs5536_acc.c
@@ -0,0 +1,140 @@
+/*
+ * the ACC Virtual Support Module of AMD CS5536
+ *
+ * Copyright (C) 2007 Lemote, Inc.
+ * Author : jlliu, liujl@lemote.com
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <cs5536/cs5536.h>
+#include <cs5536/cs5536_pci.h>
+
+void pci_acc_write_reg(int reg, u32 value)
+{
+ u32 hi = 0, lo = value;
+
+ switch (reg) {
+ case PCI_COMMAND:
+ _rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
+ if (value & PCI_COMMAND_MASTER)
+ lo |= (0x03 << 8);
+ else
+ lo &= ~(0x03 << 8);
+ _wrmsr(GLIU_MSR_REG(GLIU_PAE), hi, lo);
+ break;
+ case PCI_STATUS:
+ if (value & PCI_STATUS_PARITY) {
+ _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+ if (lo & SB_PARE_ERR_FLAG) {
+ lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG;
+ _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
+ }
+ }
+ break;
+ case PCI_BAR0_REG:
+ if (value == PCI_BAR_RANGE_MASK) {
+ _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+ lo |= SOFT_BAR_ACC_FLAG;
+ _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+ } else if (value & 0x01) {
+ value &= 0xfffffffc;
+ hi = 0xA0000000 | ((value & 0x000ff000) >> 12);
+ lo = 0x000fff80 | ((value & 0x00000fff) << 20);
+ _wrmsr(GLIU_MSR_REG(GLIU_IOD_BM1), hi, lo);
+ }
+ break;
+ case PCI_ACC_INT_REG:
+ _rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo);
+ /* disable all the usb interrupt in PIC */
+ lo &= ~(0xf << PIC_YSEL_LOW_ACC_SHIFT);
+ if (value) /* enable all the acc interrupt in PIC */
+ lo |= (CS5536_ACC_INTR << PIC_YSEL_LOW_ACC_SHIFT);
+ _wrmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), hi, lo);
+ break;
+ default:
+ break;
+ }
+}
+
+u32 pci_acc_read_reg(int reg)
+{
+ u32 hi, lo;
+ u32 conf_data = 0;
+
+ switch (reg) {
+ case PCI_VENDOR_ID:
+ conf_data =
+ CFG_PCI_VENDOR_ID(CS5536_ACC_DEVICE_ID, CS5536_VENDOR_ID);
+ break;
+ case PCI_COMMAND:
+ _rdmsr(GLIU_MSR_REG(GLIU_IOD_BM1), &hi, &lo);
+ if (((lo & 0xfff00000) || (hi & 0x000000ff))
+ && ((hi & 0xf0000000) == 0xa0000000))
+ conf_data |= PCI_COMMAND_IO;
+ _rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
+ if ((lo & 0x300) == 0x300)
+ conf_data |= PCI_COMMAND_MASTER;
+ break;
+ case PCI_STATUS:
+ conf_data |= PCI_STATUS_66MHZ;
+ conf_data |= PCI_STATUS_FAST_BACK;
+ _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+ if (lo & SB_PARE_ERR_FLAG)
+ conf_data |= PCI_STATUS_PARITY;
+ conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+ break;
+ case PCI_CLASS_REVISION:
+ _rdmsr(ACC_MSR_REG(ACC_CAP), &hi, &lo);
+ conf_data = lo & 0x000000ff;
+ conf_data |= (CS5536_ACC_CLASS_CODE << 8);
+ break;
+ case PCI_CACHE_LINE_SIZE:
+ conf_data =
+ CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
+ PCI_NORMAL_LATENCY_TIMER);
+ break;
+ case PCI_BAR0_REG:
+ _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+ if (lo & SOFT_BAR_ACC_FLAG) {
+ conf_data = CS5536_ACC_RANGE |
+ PCI_BASE_ADDRESS_SPACE_IO;
+ lo &= ~SOFT_BAR_ACC_FLAG;
+ _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+ } else {
+ _rdmsr(GLIU_MSR_REG(GLIU_IOD_BM1), &hi, &lo);
+ conf_data = (hi & 0x000000ff) << 12;
+ conf_data |= (lo & 0xfff00000) >> 20;
+ conf_data |= 0x01;
+ conf_data &= ~0x02;
+ }
+ break;
+ case PCI_CARDBUS_CIS:
+ conf_data = PCI_CARDBUS_CIS_POINTER;
+ break;
+ case PCI_SUBSYSTEM_VENDOR_ID:
+ conf_data =
+ CFG_PCI_VENDOR_ID(CS5536_ACC_SUB_ID, CS5536_SUB_VENDOR_ID);
+ break;
+ case PCI_ROM_ADDRESS:
+ conf_data = PCI_EXPANSION_ROM_BAR;
+ break;
+ case PCI_CAPABILITY_LIST:
+ conf_data = PCI_CAPLIST_USB_POINTER;
+ break;
+ case PCI_INTERRUPT_LINE:
+ conf_data =
+ CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_ACC_INTR);
+ break;
+ default:
+ break;
+ }
+
+ return conf_data;
+}
diff --git a/arch/mips/loongson/common/cs5536/cs5536_ehci.c b/arch/mips/loongson/common/cs5536/cs5536_ehci.c
new file mode 100644
index 00000000..5b5cbba6
--- /dev/null
+++ b/arch/mips/loongson/common/cs5536/cs5536_ehci.c
@@ -0,0 +1,160 @@
+/*
+ * the EHCI Virtual Support Module of AMD CS5536
+ *
+ * Copyright (C) 2007 Lemote, Inc.
+ * Author : jlliu, liujl@lemote.com
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <cs5536/cs5536.h>
+#include <cs5536/cs5536_pci.h>
+
+void pci_ehci_write_reg(int reg, u32 value)
+{
+ u32 hi = 0, lo = value;
+
+ switch (reg) {
+ case PCI_COMMAND:
+ _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+ if (value & PCI_COMMAND_MASTER)
+ hi |= PCI_COMMAND_MASTER;
+ else
+ hi &= ~PCI_COMMAND_MASTER;
+
+ if (value & PCI_COMMAND_MEMORY)
+ hi |= PCI_COMMAND_MEMORY;
+ else
+ hi &= ~PCI_COMMAND_MEMORY;
+ _wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
+ break;
+ case PCI_STATUS:
+ if (value & PCI_STATUS_PARITY) {
+ _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+ if (lo & SB_PARE_ERR_FLAG) {
+ lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG;
+ _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
+ }
+ }
+ break;
+ case PCI_BAR0_REG:
+ if (value == PCI_BAR_RANGE_MASK) {
+ _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+ lo |= SOFT_BAR_EHCI_FLAG;
+ _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+ } else if ((value & 0x01) == 0x00) {
+ _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+ lo = value;
+ _wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
+
+ value &= 0xfffffff0;
+ hi = 0x40000000 | ((value & 0xff000000) >> 24);
+ lo = 0x000fffff | ((value & 0x00fff000) << 8);
+ _wrmsr(GLIU_MSR_REG(GLIU_P2D_BM4), hi, lo);
+ }
+ break;
+ case PCI_EHCI_LEGSMIEN_REG:
+ _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+ hi &= 0x003f0000;
+ hi |= (value & 0x3f) << 16;
+ _wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
+ break;
+ case PCI_EHCI_FLADJ_REG:
+ _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+ hi &= ~0x00003f00;
+ hi |= value & 0x00003f00;
+ _wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
+ break;
+ default:
+ break;
+ }
+}
+
+u32 pci_ehci_read_reg(int reg)
+{
+ u32 conf_data = 0;
+ u32 hi, lo;
+
+ switch (reg) {
+ case PCI_VENDOR_ID:
+ conf_data =
+ CFG_PCI_VENDOR_ID(CS5536_EHCI_DEVICE_ID, CS5536_VENDOR_ID);
+ break;
+ case PCI_COMMAND:
+ _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+ if (hi & PCI_COMMAND_MASTER)
+ conf_data |= PCI_COMMAND_MASTER;
+ if (hi & PCI_COMMAND_MEMORY)
+ conf_data |= PCI_COMMAND_MEMORY;
+ break;
+ case PCI_STATUS:
+ conf_data |= PCI_STATUS_66MHZ;
+ conf_data |= PCI_STATUS_FAST_BACK;
+ _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+ if (lo & SB_PARE_ERR_FLAG)
+ conf_data |= PCI_STATUS_PARITY;
+ conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+ break;
+ case PCI_CLASS_REVISION:
+ _rdmsr(USB_MSR_REG(USB_CAP), &hi, &lo);
+ conf_data = lo & 0x000000ff;
+ conf_data |= (CS5536_EHCI_CLASS_CODE << 8);
+ break;
+ case PCI_CACHE_LINE_SIZE:
+ conf_data =
+ CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
+ PCI_NORMAL_LATENCY_TIMER);
+ break;
+ case PCI_BAR0_REG:
+ _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+ if (lo & SOFT_BAR_EHCI_FLAG) {
+ conf_data = CS5536_EHCI_RANGE |
+ PCI_BASE_ADDRESS_SPACE_MEMORY;
+ lo &= ~SOFT_BAR_EHCI_FLAG;
+ _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+ } else {
+ _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+ conf_data = lo & 0xfffff000;
+ }
+ break;
+ case PCI_CARDBUS_CIS:
+ conf_data = PCI_CARDBUS_CIS_POINTER;
+ break;
+ case PCI_SUBSYSTEM_VENDOR_ID:
+ conf_data =
+ CFG_PCI_VENDOR_ID(CS5536_EHCI_SUB_ID, CS5536_SUB_VENDOR_ID);
+ break;
+ case PCI_ROM_ADDRESS:
+ conf_data = PCI_EXPANSION_ROM_BAR;
+ break;
+ case PCI_CAPABILITY_LIST:
+ conf_data = PCI_CAPLIST_USB_POINTER;
+ break;
+ case PCI_INTERRUPT_LINE:
+ conf_data =
+ CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
+ break;
+ case PCI_EHCI_LEGSMIEN_REG:
+ _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+ conf_data = (hi & 0x003f0000) >> 16;
+ break;
+ case PCI_EHCI_LEGSMISTS_REG:
+ _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+ conf_data = (hi & 0x3f000000) >> 24;
+ break;
+ case PCI_EHCI_FLADJ_REG:
+ _rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+ conf_data = hi & 0x00003f00;
+ break;
+ default:
+ break;
+ }
+
+ return conf_data;
+}
diff --git a/arch/mips/loongson/common/cs5536/cs5536_ide.c b/arch/mips/loongson/common/cs5536/cs5536_ide.c
new file mode 100644
index 00000000..681d1291
--- /dev/null
+++ b/arch/mips/loongson/common/cs5536/cs5536_ide.c
@@ -0,0 +1,192 @@
+/*
+ * the IDE Virtual Support Module of AMD CS5536
+ *
+ * Copyright (C) 2007 Lemote, Inc.
+ * Author : jlliu, liujl@lemote.com
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <cs5536/cs5536.h>
+#include <cs5536/cs5536_pci.h>
+
+void pci_ide_write_reg(int reg, u32 value)
+{
+ u32 hi = 0, lo = value;
+
+ switch (reg) {
+ case PCI_COMMAND:
+ _rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
+ if (value & PCI_COMMAND_MASTER)
+ lo |= (0x03 << 4);
+ else
+ lo &= ~(0x03 << 4);
+ _wrmsr(GLIU_MSR_REG(GLIU_PAE), hi, lo);
+ break;
+ case PCI_STATUS:
+ if (value & PCI_STATUS_PARITY) {
+ _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+ if (lo & SB_PARE_ERR_FLAG) {
+ lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG;
+ _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
+ }
+ }
+ break;
+ case PCI_CACHE_LINE_SIZE:
+ value &= 0x0000ff00;
+ _rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
+ hi &= 0xffffff00;
+ hi |= (value >> 8);
+ _wrmsr(SB_MSR_REG(SB_CTRL), hi, lo);
+ break;
+ case PCI_BAR4_REG:
+ if (value == PCI_BAR_RANGE_MASK) {
+ _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+ lo |= SOFT_BAR_IDE_FLAG;
+ _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+ } else if (value & 0x01) {
+ _rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
+ lo = (value & 0xfffffff0) | 0x1;
+ _wrmsr(IDE_MSR_REG(IDE_IO_BAR), hi, lo);
+
+ value &= 0xfffffffc;
+ hi = 0x60000000 | ((value & 0x000ff000) >> 12);
+ lo = 0x000ffff0 | ((value & 0x00000fff) << 20);
+ _wrmsr(GLIU_MSR_REG(GLIU_IOD_BM2), hi, lo);
+ }
+ break;
+ case PCI_IDE_CFG_REG:
+ if (value == CS5536_IDE_FLASH_SIGNATURE) {
+ _rdmsr(DIVIL_MSR_REG(DIVIL_BALL_OPTS), &hi, &lo);
+ lo |= 0x01;
+ _wrmsr(DIVIL_MSR_REG(DIVIL_BALL_OPTS), hi, lo);
+ } else {
+ _rdmsr(IDE_MSR_REG(IDE_CFG), &hi, &lo);
+ lo = value;
+ _wrmsr(IDE_MSR_REG(IDE_CFG), hi, lo);
+ }
+ break;
+ case PCI_IDE_DTC_REG:
+ _rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo);
+ lo = value;
+ _wrmsr(IDE_MSR_REG(IDE_DTC), hi, lo);
+ break;
+ case PCI_IDE_CAST_REG:
+ _rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo);
+ lo = value;
+ _wrmsr(IDE_MSR_REG(IDE_CAST), hi, lo);
+ break;
+ case PCI_IDE_ETC_REG:
+ _rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
+ lo = value;
+ _wrmsr(IDE_MSR_REG(IDE_ETC), hi, lo);
+ break;
+ case PCI_IDE_PM_REG:
+ _rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
+ lo = value;
+ _wrmsr(IDE_MSR_REG(IDE_INTERNAL_PM), hi, lo);
+ break;
+ default:
+ break;
+ }
+}
+
+u32 pci_ide_read_reg(int reg)
+{
+ u32 conf_data = 0;
+ u32 hi, lo;
+
+ switch (reg) {
+ case PCI_VENDOR_ID:
+ conf_data =
+ CFG_PCI_VENDOR_ID(CS5536_IDE_DEVICE_ID, CS5536_VENDOR_ID);
+ break;
+ case PCI_COMMAND:
+ _rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
+ if (lo & 0xfffffff0)
+ conf_data |= PCI_COMMAND_IO;
+ _rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
+ if ((lo & 0x30) == 0x30)
+ conf_data |= PCI_COMMAND_MASTER;
+ break;
+ case PCI_STATUS:
+ conf_data |= PCI_STATUS_66MHZ;
+ conf_data |= PCI_STATUS_FAST_BACK;
+ _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+ if (lo & SB_PARE_ERR_FLAG)
+ conf_data |= PCI_STATUS_PARITY;
+ conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+ break;
+ case PCI_CLASS_REVISION:
+ _rdmsr(IDE_MSR_REG(IDE_CAP), &hi, &lo);
+ conf_data = lo & 0x000000ff;
+ conf_data |= (CS5536_IDE_CLASS_CODE << 8);
+ break;
+ case PCI_CACHE_LINE_SIZE:
+ _rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
+ hi &= 0x000000f8;
+ conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE, hi);
+ break;
+ case PCI_BAR4_REG:
+ _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+ if (lo & SOFT_BAR_IDE_FLAG) {
+ conf_data = CS5536_IDE_RANGE |
+ PCI_BASE_ADDRESS_SPACE_IO;
+ lo &= ~SOFT_BAR_IDE_FLAG;
+ _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+ } else {
+ _rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
+ conf_data = lo & 0xfffffff0;
+ conf_data |= 0x01;
+ conf_data &= ~0x02;
+ }
+ break;
+ case PCI_CARDBUS_CIS:
+ conf_data = PCI_CARDBUS_CIS_POINTER;
+ break;
+ case PCI_SUBSYSTEM_VENDOR_ID:
+ conf_data =
+ CFG_PCI_VENDOR_ID(CS5536_IDE_SUB_ID, CS5536_SUB_VENDOR_ID);
+ break;
+ case PCI_ROM_ADDRESS:
+ conf_data = PCI_EXPANSION_ROM_BAR;
+ break;
+ case PCI_CAPABILITY_LIST:
+ conf_data = PCI_CAPLIST_POINTER;
+ break;
+ case PCI_INTERRUPT_LINE:
+ conf_data =
+ CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_IDE_INTR);
+ break;
+ case PCI_IDE_CFG_REG:
+ _rdmsr(IDE_MSR_REG(IDE_CFG), &hi, &lo);
+ conf_data = lo;
+ break;
+ case PCI_IDE_DTC_REG:
+ _rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo);
+ conf_data = lo;
+ break;
+ case PCI_IDE_CAST_REG:
+ _rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo);
+ conf_data = lo;
+ break;
+ case PCI_IDE_ETC_REG:
+ _rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
+ conf_data = lo;
+ break;
+ case PCI_IDE_PM_REG:
+ _rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
+ conf_data = lo;
+ break;
+ default:
+ break;
+ }
+
+ return conf_data;
+}
diff --git a/arch/mips/loongson/common/cs5536/cs5536_isa.c b/arch/mips/loongson/common/cs5536/cs5536_isa.c
new file mode 100644
index 00000000..4d9f65ab
--- /dev/null
+++ b/arch/mips/loongson/common/cs5536/cs5536_isa.c
@@ -0,0 +1,316 @@
+/*
+ * the ISA Virtual Support Module of AMD CS5536
+ *
+ * Copyright (C) 2007 Lemote, Inc.
+ * Author : jlliu, liujl@lemote.com
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <cs5536/cs5536.h>
+#include <cs5536/cs5536_pci.h>
+
+/* common variables for PCI_ISA_READ/WRITE_BAR */
+static const u32 divil_msr_reg[6] = {
+ DIVIL_MSR_REG(DIVIL_LBAR_SMB), DIVIL_MSR_REG(DIVIL_LBAR_GPIO),
+ DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), DIVIL_MSR_REG(DIVIL_LBAR_IRQ),
+ DIVIL_MSR_REG(DIVIL_LBAR_PMS), DIVIL_MSR_REG(DIVIL_LBAR_ACPI),
+};
+
+static const u32 soft_bar_flag[6] = {
+ SOFT_BAR_SMB_FLAG, SOFT_BAR_GPIO_FLAG, SOFT_BAR_MFGPT_FLAG,
+ SOFT_BAR_IRQ_FLAG, SOFT_BAR_PMS_FLAG, SOFT_BAR_ACPI_FLAG,
+};
+
+static const u32 sb_msr_reg[6] = {
+ SB_MSR_REG(SB_R0), SB_MSR_REG(SB_R1), SB_MSR_REG(SB_R2),
+ SB_MSR_REG(SB_R3), SB_MSR_REG(SB_R4), SB_MSR_REG(SB_R5),
+};
+
+static const u32 bar_space_range[6] = {
+ CS5536_SMB_RANGE, CS5536_GPIO_RANGE, CS5536_MFGPT_RANGE,
+ CS5536_IRQ_RANGE, CS5536_PMS_RANGE, CS5536_ACPI_RANGE,
+};
+
+static const int bar_space_len[6] = {
+ CS5536_SMB_LENGTH, CS5536_GPIO_LENGTH, CS5536_MFGPT_LENGTH,
+ CS5536_IRQ_LENGTH, CS5536_PMS_LENGTH, CS5536_ACPI_LENGTH,
+};
+
+/*
+ * enable the divil module bar space.
+ *
+ * For all the DIVIL module LBAR, you should control the DIVIL LBAR reg
+ * and the RCONFx(0~5) reg to use the modules.
+ */
+static void divil_lbar_enable(void)
+{
+ u32 hi, lo;
+ int offset;
+
+ /*
+ * The DIVIL IRQ is not used yet. and make the RCONF0 reserved.
+ */
+
+ for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
+ _rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
+ hi |= 0x01;
+ _wrmsr(DIVIL_MSR_REG(offset), hi, lo);
+ }
+}
+
+/*
+ * disable the divil module bar space.
+ */
+static void divil_lbar_disable(void)
+{
+ u32 hi, lo;
+ int offset;
+
+ for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
+ _rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
+ hi &= ~0x01;
+ _wrmsr(DIVIL_MSR_REG(offset), hi, lo);
+ }
+}
+
+/*
+ * BAR write: write value to the n BAR
+ */
+
+void pci_isa_write_bar(int n, u32 value)
+{
+ u32 hi = 0, lo = value;
+
+ if (value == PCI_BAR_RANGE_MASK) {
+ _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+ lo |= soft_bar_flag[n];
+ _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+ } else if (value & 0x01) {
+ /* NATIVE reg */
+ hi = 0x0000f001;
+ lo &= bar_space_range[n];
+ _wrmsr(divil_msr_reg[n], hi, lo);
+
+ /* RCONFx is 4bytes in units for I/O space */
+ hi = ((value & 0x000ffffc) << 12) |
+ ((bar_space_len[n] - 4) << 12) | 0x01;
+ lo = ((value & 0x000ffffc) << 12) | 0x01;
+ _wrmsr(sb_msr_reg[n], hi, lo);
+ }
+}
+
+/*
+ * BAR read: read the n BAR
+ */
+
+u32 pci_isa_read_bar(int n)
+{
+ u32 conf_data = 0;
+ u32 hi, lo;
+
+ _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+ if (lo & soft_bar_flag[n]) {
+ conf_data = bar_space_range[n] | PCI_BASE_ADDRESS_SPACE_IO;
+ lo &= ~soft_bar_flag[n];
+ _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+ } else {
+ _rdmsr(divil_msr_reg[n], &hi, &lo);
+ conf_data = lo & bar_space_range[n];
+ conf_data |= 0x01;
+ conf_data &= ~0x02;
+ }
+ return conf_data;
+}
+
+/*
+ * isa_write: ISA write transfer
+ *
+ * We assume that this is not a bus master transfer.
+ */
+void pci_isa_write_reg(int reg, u32 value)
+{
+ u32 hi = 0, lo = value;
+ u32 temp;
+
+ switch (reg) {
+ case PCI_COMMAND:
+ if (value & PCI_COMMAND_IO)
+ divil_lbar_enable();
+ else
+ divil_lbar_disable();
+ break;
+ case PCI_STATUS:
+ _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+ temp = lo & 0x0000ffff;
+ if ((value & PCI_STATUS_SIG_TARGET_ABORT) &&
+ (lo & SB_TAS_ERR_EN))
+ temp |= SB_TAS_ERR_FLAG;
+
+ if ((value & PCI_STATUS_REC_TARGET_ABORT) &&
+ (lo & SB_TAR_ERR_EN))
+ temp |= SB_TAR_ERR_FLAG;
+
+ if ((value & PCI_STATUS_REC_MASTER_ABORT)
+ && (lo & SB_MAR_ERR_EN))
+ temp |= SB_MAR_ERR_FLAG;
+
+ if ((value & PCI_STATUS_DETECTED_PARITY)
+ && (lo & SB_PARE_ERR_EN))
+ temp |= SB_PARE_ERR_FLAG;
+
+ lo = temp;
+ _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
+ break;
+ case PCI_CACHE_LINE_SIZE:
+ value &= 0x0000ff00;
+ _rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
+ hi &= 0xffffff00;
+ hi |= (value >> 8);
+ _wrmsr(SB_MSR_REG(SB_CTRL), hi, lo);
+ break;
+ case PCI_BAR0_REG:
+ pci_isa_write_bar(0, value);
+ break;
+ case PCI_BAR1_REG:
+ pci_isa_write_bar(1, value);
+ break;
+ case PCI_BAR2_REG:
+ pci_isa_write_bar(2, value);
+ break;
+ case PCI_BAR3_REG:
+ pci_isa_write_bar(3, value);
+ break;
+ case PCI_BAR4_REG:
+ pci_isa_write_bar(4, value);
+ break;
+ case PCI_BAR5_REG:
+ pci_isa_write_bar(5, value);
+ break;
+ case PCI_UART1_INT_REG:
+ _rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);
+ /* disable uart1 interrupt in PIC */
+ lo &= ~(0xf << 24);
+ if (value) /* enable uart1 interrupt in PIC */
+ lo |= (CS5536_UART1_INTR << 24);
+ _wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo);
+ break;
+ case PCI_UART2_INT_REG:
+ _rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);
+ /* disable uart2 interrupt in PIC */
+ lo &= ~(0xf << 28);
+ if (value) /* enable uart2 interrupt in PIC */
+ lo |= (CS5536_UART2_INTR << 28);
+ _wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo);
+ break;
+ case PCI_ISA_FIXUP_REG:
+ if (value) {
+ /* enable the TARGET ABORT/MASTER ABORT etc. */
+ _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+ lo |= 0x00000063;
+ _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
+ }
+
+ default:
+ /* ALL OTHER PCI CONFIG SPACE HEADER IS NOT IMPLEMENTED. */
+ break;
+ }
+}
+
+/*
+ * isa_read: ISA read transfers
+ *
+ * We assume that this is not a bus master transfer.
+ */
+u32 pci_isa_read_reg(int reg)
+{
+ u32 conf_data = 0;
+ u32 hi, lo;
+
+ switch (reg) {
+ case PCI_VENDOR_ID:
+ conf_data =
+ CFG_PCI_VENDOR_ID(CS5536_ISA_DEVICE_ID, CS5536_VENDOR_ID);
+ break;
+ case PCI_COMMAND:
+ /* we just check the first LBAR for the IO enable bit, */
+ /* maybe we should changed later. */
+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), &hi, &lo);
+ if (hi & 0x01)
+ conf_data |= PCI_COMMAND_IO;
+ break;
+ case PCI_STATUS:
+ conf_data |= PCI_STATUS_66MHZ;
+ conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+ conf_data |= PCI_STATUS_FAST_BACK;
+
+ _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+ if (lo & SB_TAS_ERR_FLAG)
+ conf_data |= PCI_STATUS_SIG_TARGET_ABORT;
+ if (lo & SB_TAR_ERR_FLAG)
+ conf_data |= PCI_STATUS_REC_TARGET_ABORT;
+ if (lo & SB_MAR_ERR_FLAG)
+ conf_data |= PCI_STATUS_REC_MASTER_ABORT;
+ if (lo & SB_PARE_ERR_FLAG)
+ conf_data |= PCI_STATUS_DETECTED_PARITY;
+ break;
+ case PCI_CLASS_REVISION:
+ _rdmsr(GLCP_MSR_REG(GLCP_CHIP_REV_ID), &hi, &lo);
+ conf_data = lo & 0x000000ff;
+ conf_data |= (CS5536_ISA_CLASS_CODE << 8);
+ break;
+ case PCI_CACHE_LINE_SIZE:
+ _rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
+ hi &= 0x000000f8;
+ conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_BRIDGE_HEADER_TYPE, hi);
+ break;
+ /*
+ * we only use the LBAR of DIVIL, no RCONF used.
+ * all of them are IO space.
+ */
+ case PCI_BAR0_REG:
+ return pci_isa_read_bar(0);
+ break;
+ case PCI_BAR1_REG:
+ return pci_isa_read_bar(1);
+ break;
+ case PCI_BAR2_REG:
+ return pci_isa_read_bar(2);
+ break;
+ case PCI_BAR3_REG:
+ break;
+ case PCI_BAR4_REG:
+ return pci_isa_read_bar(4);
+ break;
+ case PCI_BAR5_REG:
+ return pci_isa_read_bar(5);
+ break;
+ case PCI_CARDBUS_CIS:
+ conf_data = PCI_CARDBUS_CIS_POINTER;
+ break;
+ case PCI_SUBSYSTEM_VENDOR_ID:
+ conf_data =
+ CFG_PCI_VENDOR_ID(CS5536_ISA_SUB_ID, CS5536_SUB_VENDOR_ID);
+ break;
+ case PCI_ROM_ADDRESS:
+ conf_data = PCI_EXPANSION_ROM_BAR;
+ break;
+ case PCI_CAPABILITY_LIST:
+ conf_data = PCI_CAPLIST_POINTER;
+ break;
+ case PCI_INTERRUPT_LINE:
+ /* no interrupt used here */
+ conf_data = CFG_PCI_INTERRUPT_LINE(0x00, 0x00);
+ break;
+ default:
+ break;
+ }
+
+ return conf_data;
+}
diff --git a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
new file mode 100644
index 00000000..5d1f48fa
--- /dev/null
+++ b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
@@ -0,0 +1,214 @@
+/*
+ * CS5536 General timer functions
+ *
+ * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
+ * Author: Yanhua, yanh@lemote.com
+ *
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu zhangjin, wuzhangjin@gmail.com
+ *
+ * Reference: AMD Geode(TM) CS5536 Companion Device Data Book
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+
+#include <asm/time.h>
+
+#include <cs5536/cs5536_mfgpt.h>
+
+DEFINE_SPINLOCK(mfgpt_lock);
+EXPORT_SYMBOL(mfgpt_lock);
+
+static u32 mfgpt_base;
+
+/*
+ * Initialize the MFGPT timer.
+ *
+ * This is also called after resume to bring the MFGPT into operation again.
+ */
+
+/* disable counter */
+void disable_mfgpt0_counter(void)
+{
+ outw(inw(MFGPT0_SETUP) & 0x7fff, MFGPT0_SETUP);
+}
+EXPORT_SYMBOL(disable_mfgpt0_counter);
+
+/* enable counter, comparator2 to event mode, 14.318MHz clock */
+void enable_mfgpt0_counter(void)
+{
+ outw(0xe310, MFGPT0_SETUP);
+}
+EXPORT_SYMBOL(enable_mfgpt0_counter);
+
+static void init_mfgpt_timer(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ spin_lock(&mfgpt_lock);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ outw(COMPARE, MFGPT0_CMP2); /* set comparator2 */
+ outw(0, MFGPT0_CNT); /* set counter to 0 */
+ enable_mfgpt0_counter();
+ break;
+
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ if (evt->mode == CLOCK_EVT_MODE_PERIODIC ||
+ evt->mode == CLOCK_EVT_MODE_ONESHOT)
+ disable_mfgpt0_counter();
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* The oneshot mode have very high deviation, Not use it! */
+ break;
+
+ case CLOCK_EVT_MODE_RESUME:
+ /* Nothing to do here */
+ break;
+ }
+ spin_unlock(&mfgpt_lock);
+}
+
+static struct clock_event_device mfgpt_clockevent = {
+ .name = "mfgpt",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+ .set_mode = init_mfgpt_timer,
+ .irq = CS5536_MFGPT_INTR,
+};
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+ u32 basehi;
+
+ /*
+ * get MFGPT base address
+ *
+ * NOTE: do not remove me, it's need for the value of mfgpt_base is
+ * variable
+ */
+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
+
+ /* ack */
+ outw(inw(MFGPT0_SETUP) | 0x4000, MFGPT0_SETUP);
+
+ mfgpt_clockevent.event_handler(&mfgpt_clockevent);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction irq5 = {
+ .handler = timer_interrupt,
+ .flags = IRQF_NOBALANCING | IRQF_TIMER,
+ .name = "timer"
+};
+
+/*
+ * Initialize the conversion factor and the min/max deltas of the clock event
+ * structure and register the clock event source with the framework.
+ */
+void __init setup_mfgpt0_timer(void)
+{
+ u32 basehi;
+ struct clock_event_device *cd = &mfgpt_clockevent;
+ unsigned int cpu = smp_processor_id();
+
+ cd->cpumask = cpumask_of(cpu);
+ clockevent_set_clock(cd, MFGPT_TICK_RATE);
+ cd->max_delta_ns = clockevent_delta2ns(0xffff, cd);
+ cd->min_delta_ns = clockevent_delta2ns(0xf, cd);
+
+ /* Enable MFGPT0 Comparator 2 Output to the Interrupt Mapper */
+ _wrmsr(DIVIL_MSR_REG(MFGPT_IRQ), 0, 0x100);
+
+ /* Enable Interrupt Gate 5 */
+ _wrmsr(DIVIL_MSR_REG(PIC_ZSEL_LOW), 0, 0x50000);
+
+ /* get MFGPT base address */
+ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
+
+ clockevents_register_device(cd);
+
+ setup_irq(CS5536_MFGPT_INTR, &irq5);
+}
+
+/*
+ * Since the MFGPT overflows every tick, its not very useful
+ * to just read by itself. So use jiffies to emulate a free
+ * running counter:
+ */
+static cycle_t mfgpt_read(struct clocksource *cs)
+{
+ unsigned long flags;
+ int count;
+ u32 jifs;
+ static int old_count;
+ static u32 old_jifs;
+
+ spin_lock_irqsave(&mfgpt_lock, flags);
+ /*
+ * Although our caller may have the read side of xtime_lock,
+ * this is now a seqlock, and we are cheating in this routine
+ * by having side effects on state that we cannot undo if
+ * there is a collision on the seqlock and our caller has to
+ * retry. (Namely, old_jifs and old_count.) So we must treat
+ * jiffies as volatile despite the lock. We read jiffies
+ * before latching the timer count to guarantee that although
+ * the jiffies value might be older than the count (that is,
+ * the counter may underflow between the last point where
+ * jiffies was incremented and the point where we latch the
+ * count), it cannot be newer.
+ */
+ jifs = jiffies;
+ /* read the count */
+ count = inw(MFGPT0_CNT);
+
+ /*
+ * It's possible for count to appear to go the wrong way for this
+ * reason:
+ *
+ * The timer counter underflows, but we haven't handled the resulting
+ * interrupt and incremented jiffies yet.
+ *
+ * Previous attempts to handle these cases intelligently were buggy, so
+ * we just do the simple thing now.
+ */
+ if (count < old_count && jifs == old_jifs)
+ count = old_count;
+
+ old_count = count;
+ old_jifs = jifs;
+
+ spin_unlock_irqrestore(&mfgpt_lock, flags);
+
+ return (cycle_t) (jifs * COMPARE) + count;
+}
+
+static struct clocksource clocksource_mfgpt = {
+ .name = "mfgpt",
+ .rating = 120, /* Functional for real use, but not desired */
+ .read = mfgpt_read,
+ .mask = CLOCKSOURCE_MASK(32),
+};
+
+int __init init_mfgpt_clocksource(void)
+{
+ if (num_possible_cpus() > 1) /* MFGPT does not scale! */
+ return 0;
+
+ return clocksource_register_hz(&clocksource_mfgpt, MFGPT_TICK_RATE);
+}
+
+arch_initcall(init_mfgpt_clocksource);
diff --git a/arch/mips/loongson/common/cs5536/cs5536_ohci.c b/arch/mips/loongson/common/cs5536/cs5536_ohci.c
new file mode 100644
index 00000000..bdedf512
--- /dev/null
+++ b/arch/mips/loongson/common/cs5536/cs5536_ohci.c
@@ -0,0 +1,149 @@
+/*
+ * the OHCI Virtual Support Module of AMD CS5536
+ *
+ * Copyright (C) 2007 Lemote, Inc.
+ * Author : jlliu, liujl@lemote.com
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <cs5536/cs5536.h>
+#include <cs5536/cs5536_pci.h>
+
+void pci_ohci_write_reg(int reg, u32 value)
+{
+ u32 hi = 0, lo = value;
+
+ switch (reg) {
+ case PCI_COMMAND:
+ _rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
+ if (value & PCI_COMMAND_MASTER)
+ hi |= PCI_COMMAND_MASTER;
+ else
+ hi &= ~PCI_COMMAND_MASTER;
+
+ if (value & PCI_COMMAND_MEMORY)
+ hi |= PCI_COMMAND_MEMORY;
+ else
+ hi &= ~PCI_COMMAND_MEMORY;
+ _wrmsr(USB_MSR_REG(USB_OHCI), hi, lo);
+ break;
+ case PCI_STATUS:
+ if (value & PCI_STATUS_PARITY) {
+ _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+ if (lo & SB_PARE_ERR_FLAG) {
+ lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG;
+ _wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
+ }
+ }
+ break;
+ case PCI_BAR0_REG:
+ if (value == PCI_BAR_RANGE_MASK) {
+ _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+ lo |= SOFT_BAR_OHCI_FLAG;
+ _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+ } else if ((value & 0x01) == 0x00) {
+ _rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
+ lo = value;
+ _wrmsr(USB_MSR_REG(USB_OHCI), hi, lo);
+
+ value &= 0xfffffff0;
+ hi = 0x40000000 | ((value & 0xff000000) >> 24);
+ lo = 0x000fffff | ((value & 0x00fff000) << 8);
+ _wrmsr(GLIU_MSR_REG(GLIU_P2D_BM3), hi, lo);
+ }
+ break;
+ case PCI_OHCI_INT_REG:
+ _rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo);
+ lo &= ~(0xf << PIC_YSEL_LOW_USB_SHIFT);
+ if (value) /* enable all the usb interrupt in PIC */
+ lo |= (CS5536_USB_INTR << PIC_YSEL_LOW_USB_SHIFT);
+ _wrmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), hi, lo);
+ break;
+ default:
+ break;
+ }
+}
+
+u32 pci_ohci_read_reg(int reg)
+{
+ u32 conf_data = 0;
+ u32 hi, lo;
+
+ switch (reg) {
+ case PCI_VENDOR_ID:
+ conf_data =
+ CFG_PCI_VENDOR_ID(CS5536_OHCI_DEVICE_ID, CS5536_VENDOR_ID);
+ break;
+ case PCI_COMMAND:
+ _rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
+ if (hi & PCI_COMMAND_MASTER)
+ conf_data |= PCI_COMMAND_MASTER;
+ if (hi & PCI_COMMAND_MEMORY)
+ conf_data |= PCI_COMMAND_MEMORY;
+ break;
+ case PCI_STATUS:
+ conf_data |= PCI_STATUS_66MHZ;
+ conf_data |= PCI_STATUS_FAST_BACK;
+ _rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
+ if (lo & SB_PARE_ERR_FLAG)
+ conf_data |= PCI_STATUS_PARITY;
+ conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
+ break;
+ case PCI_CLASS_REVISION:
+ _rdmsr(USB_MSR_REG(USB_CAP), &hi, &lo);
+ conf_data = lo & 0x000000ff;
+ conf_data |= (CS5536_OHCI_CLASS_CODE << 8);
+ break;
+ case PCI_CACHE_LINE_SIZE:
+ conf_data =
+ CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
+ PCI_NORMAL_LATENCY_TIMER);
+ break;
+ case PCI_BAR0_REG:
+ _rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
+ if (lo & SOFT_BAR_OHCI_FLAG) {
+ conf_data = CS5536_OHCI_RANGE |
+ PCI_BASE_ADDRESS_SPACE_MEMORY;
+ lo &= ~SOFT_BAR_OHCI_FLAG;
+ _wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
+ } else {
+ _rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
+ conf_data = lo & 0xffffff00;
+ conf_data &= ~0x0000000f; /* 32bit mem */
+ }
+ break;
+ case PCI_CARDBUS_CIS:
+ conf_data = PCI_CARDBUS_CIS_POINTER;
+ break;
+ case PCI_SUBSYSTEM_VENDOR_ID:
+ conf_data =
+ CFG_PCI_VENDOR_ID(CS5536_OHCI_SUB_ID, CS5536_SUB_VENDOR_ID);
+ break;
+ case PCI_ROM_ADDRESS:
+ conf_data = PCI_EXPANSION_ROM_BAR;
+ break;
+ case PCI_CAPABILITY_LIST:
+ conf_data = PCI_CAPLIST_USB_POINTER;
+ break;
+ case PCI_INTERRUPT_LINE:
+ conf_data =
+ CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
+ break;
+ case PCI_OHCI_INT_REG:
+ _rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo);
+ if ((lo & 0x00000f00) == CS5536_USB_INTR)
+ conf_data = 1;
+ break;
+ default:
+ break;
+ }
+
+ return conf_data;
+}
diff --git a/arch/mips/loongson/common/cs5536/cs5536_pci.c b/arch/mips/loongson/common/cs5536/cs5536_pci.c
new file mode 100644
index 00000000..6dfeab11
--- /dev/null
+++ b/arch/mips/loongson/common/cs5536/cs5536_pci.c
@@ -0,0 +1,87 @@
+/*
+ * read/write operation to the PCI config space of CS5536
+ *
+ * Copyright (C) 2007 Lemote, Inc.
+ * Author : jlliu, liujl@lemote.com
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * the Virtual Support Module(VSM) for virtulizing the PCI
+ * configure space are defined in cs5536_modulename.c respectively,
+ *
+ * after this virtulizing, user can access the PCI configure space
+ * directly as a normal multi-function PCI device which follows
+ * the PCI-2.2 spec.
+ */
+
+#include <linux/types.h>
+#include <cs5536/cs5536_vsm.h>
+
+enum {
+ CS5536_FUNC_START = -1,
+ CS5536_ISA_FUNC,
+ reserved_func,
+ CS5536_IDE_FUNC,
+ CS5536_ACC_FUNC,
+ CS5536_OHCI_FUNC,
+ CS5536_EHCI_FUNC,
+ CS5536_FUNC_END,
+};
+
+static const cs5536_pci_vsm_write vsm_conf_write[] = {
+ [CS5536_ISA_FUNC] pci_isa_write_reg,
+ [reserved_func] NULL,
+ [CS5536_IDE_FUNC] pci_ide_write_reg,
+ [CS5536_ACC_FUNC] pci_acc_write_reg,
+ [CS5536_OHCI_FUNC] pci_ohci_write_reg,
+ [CS5536_EHCI_FUNC] pci_ehci_write_reg,
+};
+
+static const cs5536_pci_vsm_read vsm_conf_read[] = {
+ [CS5536_ISA_FUNC] pci_isa_read_reg,
+ [reserved_func] NULL,
+ [CS5536_IDE_FUNC] pci_ide_read_reg,
+ [CS5536_ACC_FUNC] pci_acc_read_reg,
+ [CS5536_OHCI_FUNC] pci_ohci_read_reg,
+ [CS5536_EHCI_FUNC] pci_ehci_read_reg,
+};
+
+/*
+ * write to PCI config space and transfer it to MSR write.
+ */
+void cs5536_pci_conf_write4(int function, int reg, u32 value)
+{
+ if ((function <= CS5536_FUNC_START) || (function >= CS5536_FUNC_END))
+ return;
+ if ((reg < 0) || (reg > 0x100) || ((reg & 0x03) != 0))
+ return;
+
+ if (vsm_conf_write[function] != NULL)
+ vsm_conf_write[function](reg, value);
+}
+
+/*
+ * read PCI config space and transfer it to MSR access.
+ */
+u32 cs5536_pci_conf_read4(int function, int reg)
+{
+ u32 data = 0;
+
+ if ((function <= CS5536_FUNC_START) || (function >= CS5536_FUNC_END))
+ return 0;
+ if ((reg < 0) || ((reg & 0x03) != 0))
+ return 0;
+ if (reg > 0x100)
+ return 0xffffffff;
+
+ if (vsm_conf_read[function] != NULL)
+ data = vsm_conf_read[function](reg);
+
+ return data;
+}
diff --git a/arch/mips/loongson/common/early_printk.c b/arch/mips/loongson/common/early_printk.c
new file mode 100644
index 00000000..a71736f0
--- /dev/null
+++ b/arch/mips/loongson/common/early_printk.c
@@ -0,0 +1,41 @@
+/* early printk support
+ *
+ * Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca>
+ * Copyright (c) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/serial_reg.h>
+
+#include <loongson.h>
+
+#define PORT(base, offset) (u8 *)(base + offset)
+
+static inline unsigned int serial_in(unsigned char *base, int offset)
+{
+ return readb(PORT(base, offset));
+}
+
+static inline void serial_out(unsigned char *base, int offset, int value)
+{
+ writeb(value, PORT(base, offset));
+}
+
+void prom_putchar(char c)
+{
+ int timeout;
+ unsigned char *uart_base;
+
+ uart_base = (unsigned char *)_loongson_uart_base;
+ timeout = 1024;
+
+ while (((serial_in(uart_base, UART_LSR) & UART_LSR_THRE) == 0) &&
+ (timeout-- > 0))
+ ;
+
+ serial_out(uart_base, UART_TX, c);
+}
diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c
new file mode 100644
index 00000000..d93830ad
--- /dev/null
+++ b/arch/mips/loongson/common/env.c
@@ -0,0 +1,79 @@
+/*
+ * 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. & Insititute of Computing Technology
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ *
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/module.h>
+
+#include <asm/bootinfo.h>
+
+#include <loongson.h>
+
+unsigned long cpu_clock_freq;
+EXPORT_SYMBOL(cpu_clock_freq);
+unsigned long memsize, highmemsize;
+
+#define parse_even_earlier(res, option, p) \
+do { \
+ unsigned int tmp __maybe_unused; \
+ \
+ if (strncmp(option, (char *)p, strlen(option)) == 0) \
+ tmp = strict_strtol((char *)p + strlen(option"="), 10, &res); \
+} while (0)
+
+void __init prom_init_env(void)
+{
+ /* pmon passes arguments in 32bit pointers */
+ int *_prom_envp;
+ unsigned long bus_clock;
+ unsigned int processor_id;
+ long l;
+
+ /* firmware arguments are initialized in head.S */
+ _prom_envp = (int *)fw_arg2;
+
+ l = (long)*_prom_envp;
+ while (l != 0) {
+ parse_even_earlier(bus_clock, "busclock", l);
+ parse_even_earlier(cpu_clock_freq, "cpuclock", l);
+ parse_even_earlier(memsize, "memsize", l);
+ parse_even_earlier(highmemsize, "highmemsize", l);
+ _prom_envp++;
+ l = (long)*_prom_envp;
+ }
+ if (memsize == 0)
+ memsize = 256;
+ if (bus_clock == 0)
+ bus_clock = 66000000;
+ if (cpu_clock_freq == 0) {
+ processor_id = (&current_cpu_data)->processor_id;
+ switch (processor_id & PRID_REV_MASK) {
+ case PRID_REV_LOONGSON2E:
+ cpu_clock_freq = 533080000;
+ break;
+ case PRID_REV_LOONGSON2F:
+ cpu_clock_freq = 797000000;
+ break;
+ default:
+ cpu_clock_freq = 100000000;
+ break;
+ }
+ }
+
+ pr_info("busclock=%ld, cpuclock=%ld, memsize=%ld, highmemsize=%ld\n",
+ bus_clock, cpu_clock_freq, memsize, highmemsize);
+}
diff --git a/arch/mips/loongson/common/gpio.c b/arch/mips/loongson/common/gpio.c
new file mode 100644
index 00000000..e8a0ffa9
--- /dev/null
+++ b/arch/mips/loongson/common/gpio.c
@@ -0,0 +1,139 @@
+/*
+ * STLS2F GPIO Support
+ *
+ * Copyright (c) 2008 Richard Liu, STMicroelectronics <richard.liu@st.com>
+ * Copyright (c) 2008-2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <asm/types.h>
+#include <loongson.h>
+#include <linux/gpio.h>
+
+#define STLS2F_N_GPIO 4
+#define STLS2F_GPIO_IN_OFFSET 16
+
+static DEFINE_SPINLOCK(gpio_lock);
+
+int gpio_get_value(unsigned gpio)
+{
+ u32 val;
+ u32 mask;
+
+ if (gpio >= STLS2F_N_GPIO)
+ return __gpio_get_value(gpio);
+
+ mask = 1 << (gpio + STLS2F_GPIO_IN_OFFSET);
+ spin_lock(&gpio_lock);
+ val = LOONGSON_GPIODATA;
+ spin_unlock(&gpio_lock);
+
+ return ((val & mask) != 0);
+}
+EXPORT_SYMBOL(gpio_get_value);
+
+void gpio_set_value(unsigned gpio, int state)
+{
+ u32 val;
+ u32 mask;
+
+ if (gpio >= STLS2F_N_GPIO) {
+ __gpio_set_value(gpio, state);
+ return ;
+ }
+
+ mask = 1 << gpio;
+
+ spin_lock(&gpio_lock);
+ val = LOONGSON_GPIODATA;
+ if (state)
+ val |= mask;
+ else
+ val &= (~mask);
+ LOONGSON_GPIODATA = val;
+ spin_unlock(&gpio_lock);
+}
+EXPORT_SYMBOL(gpio_set_value);
+
+int gpio_cansleep(unsigned gpio)
+{
+ if (gpio < STLS2F_N_GPIO)
+ return 0;
+ else
+ return __gpio_cansleep(gpio);
+}
+EXPORT_SYMBOL(gpio_cansleep);
+
+static int ls2f_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ u32 temp;
+ u32 mask;
+
+ if (gpio >= STLS2F_N_GPIO)
+ return -EINVAL;
+
+ spin_lock(&gpio_lock);
+ mask = 1 << gpio;
+ temp = LOONGSON_GPIOIE;
+ temp |= mask;
+ LOONGSON_GPIOIE = temp;
+ spin_unlock(&gpio_lock);
+
+ return 0;
+}
+
+static int ls2f_gpio_direction_output(struct gpio_chip *chip,
+ unsigned gpio, int level)
+{
+ u32 temp;
+ u32 mask;
+
+ if (gpio >= STLS2F_N_GPIO)
+ return -EINVAL;
+
+ gpio_set_value(gpio, level);
+ spin_lock(&gpio_lock);
+ mask = 1 << gpio;
+ temp = LOONGSON_GPIOIE;
+ temp &= (~mask);
+ LOONGSON_GPIOIE = temp;
+ spin_unlock(&gpio_lock);
+
+ return 0;
+}
+
+static int ls2f_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+ return gpio_get_value(gpio);
+}
+
+static void ls2f_gpio_set_value(struct gpio_chip *chip,
+ unsigned gpio, int value)
+{
+ gpio_set_value(gpio, value);
+}
+
+static struct gpio_chip ls2f_chip = {
+ .label = "ls2f",
+ .direction_input = ls2f_gpio_direction_input,
+ .get = ls2f_gpio_get_value,
+ .direction_output = ls2f_gpio_direction_output,
+ .set = ls2f_gpio_set_value,
+ .base = 0,
+ .ngpio = STLS2F_N_GPIO,
+};
+
+static int __init ls2f_gpio_setup(void)
+{
+ return gpiochip_add(&ls2f_chip);
+}
+arch_initcall(ls2f_gpio_setup);
diff --git a/arch/mips/loongson/common/init.c b/arch/mips/loongson/common/init.c
new file mode 100644
index 00000000..19d34159
--- /dev/null
+++ b/arch/mips/loongson/common/init.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/bootmem.h>
+
+#include <loongson.h>
+
+/* Loongson CPU address windows config space base address */
+unsigned long __maybe_unused _loongson_addrwincfg_base;
+
+void __init prom_init(void)
+{
+ /* init base address of io space */
+ set_io_port_base((unsigned long)
+ ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE));
+
+#ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG
+ _loongson_addrwincfg_base = (unsigned long)
+ ioremap(LOONGSON_ADDRWINCFG_BASE, LOONGSON_ADDRWINCFG_SIZE);
+#endif
+
+ prom_init_cmdline();
+ prom_init_env();
+ prom_init_memory();
+
+ /*init the uart base address */
+ prom_init_uart_base();
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
diff --git a/arch/mips/loongson/common/irq.c b/arch/mips/loongson/common/irq.c
new file mode 100644
index 00000000..5897471d
--- /dev/null
+++ b/arch/mips/loongson/common/irq.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#include <loongson.h>
+/*
+ * the first level int-handler will jump here if it is a bonito irq
+ */
+void bonito_irqdispatch(void)
+{
+ u32 int_status;
+ int i;
+
+ /* workaround the IO dma problem: let cpu looping to allow DMA finish */
+ int_status = LOONGSON_INTISR;
+ while (int_status & (1 << 10)) {
+ udelay(1);
+ int_status = LOONGSON_INTISR;
+ }
+
+ /* Get pending sources, masked by current enables */
+ int_status = LOONGSON_INTISR & LOONGSON_INTEN;
+
+ if (int_status) {
+ i = __ffs(int_status);
+ do_IRQ(LOONGSON_IRQ_BASE + i);
+ }
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ unsigned int pending;
+
+ pending = read_c0_cause() & read_c0_status() & ST0_IM;
+
+ /* machine-specific plat_irq_dispatch */
+ mach_irq_dispatch(pending);
+}
+
+void __init arch_init_irq(void)
+{
+ /*
+ * Clear all of the interrupts while we change the able around a bit.
+ * int-handler is not on bootstrap
+ */
+ clear_c0_status(ST0_IM | ST0_BEV);
+
+ /* no steer */
+ LOONGSON_INTSTEER = 0;
+
+ /*
+ * Mask out all interrupt by writing "1" to all bit position in
+ * the interrupt reset reg.
+ */
+ LOONGSON_INTENCLR = ~0;
+
+ /* machine specific irq init */
+ mach_init_irq();
+}
diff --git a/arch/mips/loongson/common/machtype.c b/arch/mips/loongson/common/machtype.c
new file mode 100644
index 00000000..2efd5d9d
--- /dev/null
+++ b/arch/mips/loongson/common/machtype.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * Copyright (c) 2009 Zhang Le <r0bertz@gentoo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/errno.h>
+#include <asm/bootinfo.h>
+
+#include <loongson.h>
+#include <machine.h>
+
+/* please ensure the length of the machtype string is less than 50 */
+#define MACHTYPE_LEN 50
+
+static const char *system_types[] = {
+ [MACH_LOONGSON_UNKNOWN] "unknown loongson machine",
+ [MACH_LEMOTE_FL2E] "lemote-fuloong-2e-box",
+ [MACH_LEMOTE_FL2F] "lemote-fuloong-2f-box",
+ [MACH_LEMOTE_ML2F7] "lemote-mengloong-2f-7inches",
+ [MACH_LEMOTE_YL2F89] "lemote-yeeloong-2f-8.9inches",
+ [MACH_DEXXON_GDIUM2F10] "dexxon-gdium-2f",
+ [MACH_LEMOTE_NAS] "lemote-nas-2f",
+ [MACH_LEMOTE_LL2F] "lemote-lynloong-2f",
+ [MACH_LOONGSON_END] NULL,
+};
+
+const char *get_system_type(void)
+{
+ return system_types[mips_machtype];
+}
+
+void __weak __init mach_prom_init_machtype(void)
+{
+}
+
+void __init prom_init_machtype(void)
+{
+ char *p, str[MACHTYPE_LEN + 1];
+ int machtype = MACH_LEMOTE_FL2E;
+
+ mips_machtype = LOONGSON_MACHTYPE;
+
+ p = strstr(arcs_cmdline, "machtype=");
+ if (!p) {
+ mach_prom_init_machtype();
+ return;
+ }
+ p += strlen("machtype=");
+ strncpy(str, p, MACHTYPE_LEN);
+ str[MACHTYPE_LEN] = '\0';
+ p = strstr(str, " ");
+ if (p)
+ *p = '\0';
+
+ for (; system_types[machtype]; machtype++)
+ if (strstr(system_types[machtype], str)) {
+ mips_machtype = machtype;
+ break;
+ }
+}
diff --git a/arch/mips/loongson/common/mem.c b/arch/mips/loongson/common/mem.c
new file mode 100644
index 00000000..30eba600
--- /dev/null
+++ b/arch/mips/loongson/common/mem.c
@@ -0,0 +1,119 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/fs.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+
+#include <asm/bootinfo.h>
+
+#include <loongson.h>
+#include <mem.h>
+#include <pci.h>
+
+void __init prom_init_memory(void)
+{
+ add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM);
+
+ add_memory_region(memsize << 20, LOONGSON_PCI_MEM_START - (memsize <<
+ 20), BOOT_MEM_RESERVED);
+
+#ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG
+ {
+ int bit;
+
+ bit = fls(memsize + highmemsize);
+ if (bit != ffs(memsize + highmemsize))
+ bit += 20;
+ else
+ bit = bit + 20 - 1;
+
+ /* set cpu window3 to map CPU to DDR: 2G -> 2G */
+ LOONGSON_ADDRWIN_CPUTODDR(ADDRWIN_WIN3, 0x80000000ul,
+ 0x80000000ul, (1 << bit));
+ mmiowb();
+ }
+#endif /* !CONFIG_CPU_SUPPORTS_ADDRWINCFG */
+
+#ifdef CONFIG_64BIT
+ if (highmemsize > 0)
+ add_memory_region(LOONGSON_HIGHMEM_START,
+ highmemsize << 20, BOOT_MEM_RAM);
+
+ add_memory_region(LOONGSON_PCI_MEM_END + 1, LOONGSON_HIGHMEM_START -
+ LOONGSON_PCI_MEM_END - 1, BOOT_MEM_RESERVED);
+
+#endif /* !CONFIG_64BIT */
+}
+
+/* override of arch/mips/mm/cache.c: __uncached_access */
+int __uncached_access(struct file *file, unsigned long addr)
+{
+ if (file->f_flags & O_DSYNC)
+ return 1;
+
+ return addr >= __pa(high_memory) ||
+ ((addr >= LOONGSON_MMIO_MEM_START) &&
+ (addr < LOONGSON_MMIO_MEM_END));
+}
+
+#ifdef CONFIG_CPU_SUPPORTS_UNCACHED_ACCELERATED
+
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <asm/current.h>
+
+static unsigned long uca_start, uca_end;
+
+pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+ unsigned long size, pgprot_t vma_prot)
+{
+ unsigned long offset = pfn << PAGE_SHIFT;
+ unsigned long end = offset + size;
+
+ if (__uncached_access(file, offset)) {
+ if (uca_start && (offset >= uca_start) &&
+ (end <= uca_end))
+ return __pgprot((pgprot_val(vma_prot) &
+ ~_CACHE_MASK) |
+ _CACHE_UNCACHED_ACCELERATED);
+ else
+ return pgprot_noncached(vma_prot);
+ }
+ return vma_prot;
+}
+
+static int __init find_vga_mem_init(void)
+{
+ struct pci_dev *dev = 0;
+ struct resource *r;
+ int idx;
+
+ if (uca_start)
+ return 0;
+
+ for_each_pci_dev(dev) {
+ if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
+ for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) {
+ r = &dev->resource[idx];
+ if (!r->start && r->end)
+ continue;
+ if (r->flags & IORESOURCE_IO)
+ continue;
+ if (r->flags & IORESOURCE_MEM) {
+ uca_start = r->start;
+ uca_end = r->end;
+ return 0;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+late_initcall(find_vga_mem_init);
+#endif /* !CONFIG_CPU_SUPPORTS_UNCACHED_ACCELERATED */
diff --git a/arch/mips/loongson/common/pci.c b/arch/mips/loongson/common/pci.c
new file mode 100644
index 00000000..31d8c5ec
--- /dev/null
+++ b/arch/mips/loongson/common/pci.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 Lemote, Inc. & Institute of Computing Technology
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/pci.h>
+
+#include <pci.h>
+#include <loongson.h>
+
+static struct resource loongson_pci_mem_resource = {
+ .name = "pci memory space",
+ .start = LOONGSON_PCI_MEM_START,
+ .end = LOONGSON_PCI_MEM_END,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource loongson_pci_io_resource = {
+ .name = "pci io space",
+ .start = LOONGSON_PCI_IO_START,
+ .end = IO_SPACE_LIMIT,
+ .flags = IORESOURCE_IO,
+};
+
+static struct pci_controller loongson_pci_controller = {
+ .pci_ops = &loongson_pci_ops,
+ .io_resource = &loongson_pci_io_resource,
+ .mem_resource = &loongson_pci_mem_resource,
+ .mem_offset = 0x00000000UL,
+ .io_offset = 0x00000000UL,
+};
+
+static void __init setup_pcimap(void)
+{
+ /*
+ * local to PCI mapping for CPU accessing PCI space
+ * CPU address space [256M,448M] is window for accessing pci space
+ * we set pcimap_lo[0,1,2] to map it to pci space[0M,64M], [320M,448M]
+ *
+ * pcimap: PCI_MAP2 PCI_Mem_Lo2 PCI_Mem_Lo1 PCI_Mem_Lo0
+ * [<2G] [384M,448M] [320M,384M] [0M,64M]
+ */
+ LOONGSON_PCIMAP = LOONGSON_PCIMAP_PCIMAP_2 |
+ LOONGSON_PCIMAP_WIN(2, LOONGSON_PCILO2_BASE) |
+ LOONGSON_PCIMAP_WIN(1, LOONGSON_PCILO1_BASE) |
+ LOONGSON_PCIMAP_WIN(0, 0);
+
+ /*
+ * PCI-DMA to local mapping: [2G,2G+256M] -> [0M,256M]
+ */
+ LOONGSON_PCIBASE0 = 0x80000000ul; /* base: 2G -> mmap: 0M */
+ /* size: 256M, burst transmission, pre-fetch enable, 64bit */
+ LOONGSON_PCI_HIT0_SEL_L = 0xc000000cul;
+ LOONGSON_PCI_HIT0_SEL_H = 0xfffffffful;
+ LOONGSON_PCI_HIT1_SEL_L = 0x00000006ul; /* set this BAR as invalid */
+ LOONGSON_PCI_HIT1_SEL_H = 0x00000000ul;
+ LOONGSON_PCI_HIT2_SEL_L = 0x00000006ul; /* set this BAR as invalid */
+ LOONGSON_PCI_HIT2_SEL_H = 0x00000000ul;
+
+ /* avoid deadlock of PCI reading/writing lock operation */
+ LOONGSON_PCI_ISR4C = 0xd2000001ul;
+
+ /* can not change gnt to break pci transfer when device's gnt not
+ deassert for some broken device */
+ LOONGSON_PXARB_CFG = 0x00fe0105ul;
+
+#ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG
+ /*
+ * set cpu addr window2 to map CPU address space to PCI address space
+ */
+ LOONGSON_ADDRWIN_CPUTOPCI(ADDRWIN_WIN2, LOONGSON_CPU_MEM_SRC,
+ LOONGSON_PCI_MEM_DST, MMAP_CPUTOPCI_SIZE);
+#endif
+}
+
+static int __init pcibios_init(void)
+{
+ setup_pcimap();
+
+ loongson_pci_controller.io_map_base = mips_io_port_base;
+
+ register_pci_controller(&loongson_pci_controller);
+
+ return 0;
+}
+
+arch_initcall(pcibios_init);
diff --git a/arch/mips/loongson/common/platform.c b/arch/mips/loongson/common/platform.c
new file mode 100644
index 00000000..502b059d
--- /dev/null
+++ b/arch/mips/loongson/common/platform.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/smp.h>
+#include <linux/platform_device.h>
+
+static struct platform_device loongson2_cpufreq_device = {
+ .name = "loongson2_cpufreq",
+ .id = -1,
+};
+
+static int __init loongson2_cpufreq_init(void)
+{
+ struct cpuinfo_mips *c = &current_cpu_data;
+
+ /* Only 2F revision and it's successors support CPUFreq */
+ if ((c->processor_id & PRID_REV_MASK) >= PRID_REV_LOONGSON2F)
+ return platform_device_register(&loongson2_cpufreq_device);
+
+ return -ENODEV;
+}
+
+arch_initcall(loongson2_cpufreq_init);
diff --git a/arch/mips/loongson/common/pm.c b/arch/mips/loongson/common/pm.c
new file mode 100644
index 00000000..f55e07ae
--- /dev/null
+++ b/arch/mips/loongson/common/pm.c
@@ -0,0 +1,161 @@
+/*
+ * loongson-specific suspend support
+ *
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin <wuzhangjin@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+
+#include <asm/i8259.h>
+#include <asm/mipsregs.h>
+
+#include <loongson.h>
+
+static unsigned int __maybe_unused cached_master_mask; /* i8259A */
+static unsigned int __maybe_unused cached_slave_mask;
+static unsigned int __maybe_unused cached_bonito_irq_mask; /* bonito */
+
+void arch_suspend_disable_irqs(void)
+{
+ /* disable all mips events */
+ local_irq_disable();
+
+#ifdef CONFIG_I8259
+ /* disable all events of i8259A */
+ cached_slave_mask = inb(PIC_SLAVE_IMR);
+ cached_master_mask = inb(PIC_MASTER_IMR);
+
+ outb(0xff, PIC_SLAVE_IMR);
+ inb(PIC_SLAVE_IMR);
+ outb(0xff, PIC_MASTER_IMR);
+ inb(PIC_MASTER_IMR);
+#endif
+ /* disable all events of bonito */
+ cached_bonito_irq_mask = LOONGSON_INTEN;
+ LOONGSON_INTENCLR = 0xffff;
+ (void)LOONGSON_INTENCLR;
+}
+
+void arch_suspend_enable_irqs(void)
+{
+ /* enable all mips events */
+ local_irq_enable();
+#ifdef CONFIG_I8259
+ /* only enable the cached events of i8259A */
+ outb(cached_slave_mask, PIC_SLAVE_IMR);
+ outb(cached_master_mask, PIC_MASTER_IMR);
+#endif
+ /* enable all cached events of bonito */
+ LOONGSON_INTENSET = cached_bonito_irq_mask;
+ (void)LOONGSON_INTENSET;
+}
+
+/*
+ * Setup the board-specific events for waking up loongson from wait mode
+ */
+void __weak setup_wakeup_events(void)
+{
+}
+
+/*
+ * Check wakeup events
+ */
+int __weak wakeup_loongson(void)
+{
+ return 1;
+}
+
+/*
+ * If the events are really what we want to wakeup the CPU, wake it up
+ * otherwise put the CPU asleep again.
+ */
+static void wait_for_wakeup_events(void)
+{
+ while (!wakeup_loongson())
+ LOONGSON_CHIPCFG0 &= ~0x7;
+}
+
+/*
+ * Stop all perf counters
+ *
+ * $24 is the control register of Loongson perf counter
+ */
+static inline void stop_perf_counters(void)
+{
+ __write_64bit_c0_register($24, 0, 0);
+}
+
+
+static void loongson_suspend_enter(void)
+{
+ static unsigned int cached_cpu_freq;
+
+ /* setup wakeup events via enabling the IRQs */
+ setup_wakeup_events();
+
+ stop_perf_counters();
+
+ cached_cpu_freq = LOONGSON_CHIPCFG0;
+
+ /* Put CPU into wait mode */
+ LOONGSON_CHIPCFG0 &= ~0x7;
+
+ /* wait for the given events to wakeup cpu from wait mode */
+ wait_for_wakeup_events();
+
+ LOONGSON_CHIPCFG0 = cached_cpu_freq;
+ mmiowb();
+}
+
+void __weak mach_suspend(void)
+{
+}
+
+void __weak mach_resume(void)
+{
+}
+
+static int loongson_pm_enter(suspend_state_t state)
+{
+ mach_suspend();
+
+ /* processor specific suspend */
+ loongson_suspend_enter();
+
+ mach_resume();
+
+ return 0;
+}
+
+static int loongson_pm_valid_state(suspend_state_t state)
+{
+ switch (state) {
+ case PM_SUSPEND_ON:
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static const struct platform_suspend_ops loongson_pm_ops = {
+ .valid = loongson_pm_valid_state,
+ .enter = loongson_pm_enter,
+};
+
+static int __init loongson_pm_init(void)
+{
+ suspend_set_ops(&loongson_pm_ops);
+
+ return 0;
+}
+arch_initcall(loongson_pm_init);
diff --git a/arch/mips/loongson/common/reset.c b/arch/mips/loongson/common/reset.c
new file mode 100644
index 00000000..9e10d622
--- /dev/null
+++ b/arch/mips/loongson/common/reset.c
@@ -0,0 +1,70 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/reboot.h>
+
+#include <loongson.h>
+
+static inline void loongson_reboot(void)
+{
+#ifndef CONFIG_CPU_JUMP_WORKAROUNDS
+ ((void (*)(void))ioremap_nocache(LOONGSON_BOOT_BASE, 4)) ();
+#else
+ void (*func)(void);
+
+ func = (void *)ioremap_nocache(LOONGSON_BOOT_BASE, 4);
+
+ __asm__ __volatile__(
+ " .set noat \n"
+ " jr %[func] \n"
+ " .set at \n"
+ : /* No outputs */
+ : [func] "r" (func));
+#endif
+}
+
+static void loongson_restart(char *command)
+{
+ /* do preparation for reboot */
+ mach_prepare_reboot();
+
+ /* reboot via jumping to boot base address */
+ loongson_reboot();
+}
+
+static void loongson_poweroff(void)
+{
+ mach_prepare_shutdown();
+ unreachable();
+}
+
+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/loongson/common/rtc.c b/arch/mips/loongson/common/rtc.c
new file mode 100644
index 00000000..a90d87c0
--- /dev/null
+++ b/arch/mips/loongson/common/rtc.c
@@ -0,0 +1,43 @@
+/*
+ * Lemote Fuloong platform support
+ *
+ * Copyright(c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mc146818rtc.h>
+
+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/loongson/common/serial.c b/arch/mips/loongson/common/serial.c
new file mode 100644
index 00000000..75808731
--- /dev/null
+++ b/arch/mips/loongson/common/serial.c
@@ -0,0 +1,76 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org)
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Yan hua (yanhua@lemote.com)
+ * Author: Wu Zhangjin (wuzhangjin@gmail.com)
+ */
+
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#include <asm/bootinfo.h>
+
+#include <loongson.h>
+#include <machine.h>
+
+#define PORT(int) \
+{ \
+ .irq = int, \
+ .uartclk = 1843200, \
+ .iotype = UPIO_PORT, \
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \
+ .regshift = 0, \
+}
+
+#define PORT_M(int) \
+{ \
+ .irq = MIPS_CPU_IRQ_BASE + (int), \
+ .uartclk = 3686400, \
+ .iotype = UPIO_MEM, \
+ .membase = (void __iomem *)NULL, \
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \
+ .regshift = 0, \
+}
+
+static struct plat_serial8250_port uart8250_data[][2] = {
+ [MACH_LOONGSON_UNKNOWN] {},
+ [MACH_LEMOTE_FL2E] {PORT(4), {} },
+ [MACH_LEMOTE_FL2F] {PORT(3), {} },
+ [MACH_LEMOTE_ML2F7] {PORT_M(3), {} },
+ [MACH_LEMOTE_YL2F89] {PORT_M(3), {} },
+ [MACH_DEXXON_GDIUM2F10] {PORT_M(3), {} },
+ [MACH_LEMOTE_NAS] {PORT_M(3), {} },
+ [MACH_LEMOTE_LL2F] {PORT(3), {} },
+ [MACH_LOONGSON_END] {},
+};
+
+static struct platform_device uart8250_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+};
+
+static int __init serial_init(void)
+{
+ unsigned char iotype;
+
+ iotype = uart8250_data[mips_machtype][0].iotype;
+
+ if (UPIO_MEM == iotype)
+ uart8250_data[mips_machtype][0].membase =
+ (void __iomem *)_loongson_uart_base;
+ else if (UPIO_PORT == iotype)
+ uart8250_data[mips_machtype][0].iobase =
+ loongson_uart_base - LOONGSON_PCIIO_BASE;
+
+ uart8250_device.dev.platform_data = uart8250_data[mips_machtype];
+
+ return platform_device_register(&uart8250_device);
+}
+
+device_initcall(serial_init);
diff --git a/arch/mips/loongson/common/setup.c b/arch/mips/loongson/common/setup.c
new file mode 100644
index 00000000..27d826bc
--- /dev/null
+++ b/arch/mips/loongson/common/setup.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
+ * Author: Fuxin Zhang, zhangfx@lemote.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/module.h>
+
+#include <asm/wbflush.h>
+
+#include <loongson.h>
+
+#ifdef CONFIG_VT
+#include <linux/console.h>
+#include <linux/screen_info.h>
+#endif
+
+void (*__wbflush)(void);
+EXPORT_SYMBOL(__wbflush);
+
+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 __init plat_mem_setup(void)
+{
+ __wbflush = wbflush_loongson;
+
+#ifdef CONFIG_VT
+#if defined(CONFIG_VGA_CONSOLE)
+ conswitchp = &vga_con;
+
+ screen_info = (struct screen_info) {
+ .orig_x = 0,
+ .orig_y = 25,
+ .orig_video_cols = 80,
+ .orig_video_lines = 25,
+ .orig_video_isVGA = VIDEO_TYPE_VGAC,
+ .orig_video_points = 16,
+ };
+#elif defined(CONFIG_DUMMY_CONSOLE)
+ conswitchp = &dummy_con;
+#endif
+#endif
+}
diff --git a/arch/mips/loongson/common/time.c b/arch/mips/loongson/common/time.c
new file mode 100644
index 00000000..9fdd01f6
--- /dev/null
+++ b/arch/mips/loongson/common/time.c
@@ -0,0 +1,31 @@
+/*
+ * 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
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <asm/mc146818-time.h>
+#include <asm/time.h>
+
+#include <loongson.h>
+#include <cs5536/cs5536_mfgpt.h>
+
+void __init plat_time_init(void)
+{
+ /* setup mips r4k timer */
+ mips_hpt_frequency = cpu_clock_freq / 2;
+
+ setup_mfgpt0_timer();
+}
+
+void read_persistent_clock(struct timespec *ts)
+{
+ ts->tv_sec = mc146818_get_cmos_time();
+ ts->tv_nsec = 0;
+}
diff --git a/arch/mips/loongson/common/uart_base.c b/arch/mips/loongson/common/uart_base.c
new file mode 100644
index 00000000..d69ea54b
--- /dev/null
+++ b/arch/mips/loongson/common/uart_base.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009 Lemote Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <asm/bootinfo.h>
+
+#include <loongson.h>
+
+/* ioremapped */
+unsigned long _loongson_uart_base;
+EXPORT_SYMBOL(_loongson_uart_base);
+/* raw */
+unsigned long loongson_uart_base;
+EXPORT_SYMBOL(loongson_uart_base);
+
+void prom_init_loongson_uart_base(void)
+{
+ switch (mips_machtype) {
+ case MACH_LEMOTE_FL2E:
+ loongson_uart_base = LOONGSON_PCIIO_BASE + 0x3f8;
+ break;
+ case MACH_LEMOTE_FL2F:
+ case MACH_LEMOTE_LL2F:
+ loongson_uart_base = LOONGSON_PCIIO_BASE + 0x2f8;
+ break;
+ case MACH_LEMOTE_ML2F7:
+ case MACH_LEMOTE_YL2F89:
+ case MACH_DEXXON_GDIUM2F10:
+ case MACH_LEMOTE_NAS:
+ default:
+ /* The CPU provided serial port */
+ loongson_uart_base = LOONGSON_LIO1_BASE + 0x3f8;
+ break;
+ }
+
+ _loongson_uart_base =
+ (unsigned long)ioremap_nocache(loongson_uart_base, 8);
+}