MIPS: Lemote 2F: Add PCI support
authorWu Zhangjin <wuzhangjin@gmail.com>
Mon, 9 Nov 2009 16:06:13 +0000 (00:06 +0800)
committerRalf Baechle <ralf@linux-mips.org>
Thu, 17 Dec 2009 01:57:12 +0000 (01:57 +0000)
PCI support for the Fuloong 2E and Lemote Loongson 2F family machines is
mostly identical with the exception of CS5536 support.

Rename ops-fuloong2e.c to ops-loongson2.c then add the CS5536 support to
share most of the source code among Loongson machines.

Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
Cc: zhangfx@lemote.com
Cc: yanh@lemote.com
Cc: huhb@lemote.com
Cc: Nicholas Mc Guire <hofrat@hofr.at>
Cc: Arnaud Patard <apatard@mandriva.com>
Cc: loongson-dev@googlegroups.com
Cc: linux-mips@linux-mips.org
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/pci/Makefile
arch/mips/pci/fixup-lemote2f.c [new file with mode: 0644]
arch/mips/pci/ops-loongson2.c [moved from arch/mips/pci/ops-fuloong2e.c with 70% similarity]

index 0610c86..c9a0dc1 100644 (file)
@@ -28,7 +28,8 @@ obj-$(CONFIG_MIPS_COBALT)     += fixup-cobalt.o
 obj-$(CONFIG_SOC_AU1500)       += fixup-au1000.o ops-au1000.o
 obj-$(CONFIG_SOC_AU1550)       += fixup-au1000.o ops-au1000.o
 obj-$(CONFIG_SOC_PNX8550)      += fixup-pnx8550.o ops-pnx8550.o
-obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-fuloong2e.o
+obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o
+obj-$(CONFIG_LEMOTE_MACH2F)    += fixup-lemote2f.o ops-loongson2.o
 obj-$(CONFIG_MIPS_MALTA)       += fixup-malta.o
 obj-$(CONFIG_PMC_MSP7120_GW)   += fixup-pmcmsp.o ops-pmcmsp.o
 obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o
diff --git a/arch/mips/pci/fixup-lemote2f.c b/arch/mips/pci/fixup-lemote2f.c
new file mode 100644 (file)
index 0000000..caf2ede
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2008 Lemote Technology
+ * Copyright (C) 2004 ICT CAS
+ * Author: Li xiaoyu, lixy@ict.ac.cn
+ *
+ * Copyright (C) 2007 Lemote, Inc.
+ * 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/init.h>
+#include <linux/pci.h>
+
+#include <loongson.h>
+#include <cs5536/cs5536.h>
+#include <cs5536/cs5536_pci.h>
+
+/* PCI interrupt pins
+ *
+ * These should not be changed, or you should consider loongson2f interrupt
+ * register and your pci card dispatch
+ */
+
+#define PCIA           4
+#define PCIB           5
+#define PCIC           6
+#define PCID           7
+
+/* all the pci device has the PCIA pin, check the datasheet. */
+static char irq_tab[][5] __initdata = {
+       /*      INTA    INTB    INTC    INTD */
+       {0, 0, 0, 0, 0},        /*  11: Unused */
+       {0, 0, 0, 0, 0},        /*  12: Unused */
+       {0, 0, 0, 0, 0},        /*  13: Unused */
+       {0, 0, 0, 0, 0},        /*  14: Unused */
+       {0, 0, 0, 0, 0},        /*  15: Unused */
+       {0, 0, 0, 0, 0},        /*  16: Unused */
+       {0, PCIA, 0, 0, 0},     /*  17: RTL8110-0 */
+       {0, PCIB, 0, 0, 0},     /*  18: RTL8110-1 */
+       {0, PCIC, 0, 0, 0},     /*  19: SiI3114 */
+       {0, PCID, 0, 0, 0},     /*  20: 3-ports nec usb */
+       {0, PCIA, PCIB, PCIC, PCID},    /*  21: PCI-SLOT */
+       {0, 0, 0, 0, 0},        /*  22: Unused */
+       {0, 0, 0, 0, 0},        /*  23: Unused */
+       {0, 0, 0, 0, 0},        /*  24: Unused */
+       {0, 0, 0, 0, 0},        /*  25: Unused */
+       {0, 0, 0, 0, 0},        /*  26: Unused */
+       {0, 0, 0, 0, 0},        /*  27: Unused */
+};
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+       int virq;
+
+       if ((PCI_SLOT(dev->devfn) != PCI_IDSEL_CS5536)
+           && (PCI_SLOT(dev->devfn) < 32)) {
+               virq = irq_tab[slot][pin];
+               printk(KERN_INFO "slot: %d, pin: %d, irq: %d\n", slot, pin,
+                      virq + LOONGSON_IRQ_BASE);
+               if (virq != 0)
+                       return LOONGSON_IRQ_BASE + virq;
+               else
+                       return 0;
+       } else if (PCI_SLOT(dev->devfn) == PCI_IDSEL_CS5536) {  /*  cs5536 */
+               switch (PCI_FUNC(dev->devfn)) {
+               case 2:
+                       pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
+                                             CS5536_IDE_INTR);
+                       return CS5536_IDE_INTR; /*  for IDE */
+               case 3:
+                       pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
+                                             CS5536_ACC_INTR);
+                       return CS5536_ACC_INTR; /*  for AUDIO */
+               case 4: /*  for OHCI */
+               case 5: /*  for EHCI */
+               case 6: /*  for UDC */
+               case 7: /*  for OTG */
+                       pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
+                                             CS5536_USB_INTR);
+                       return CS5536_USB_INTR;
+               }
+               return dev->irq;
+       } else {
+               printk(KERN_INFO " strange pci slot number.\n");
+               return 0;
+       }
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
+
+/* CS5536 SPEC. fixup */
+static void __init loongson_cs5536_isa_fixup(struct pci_dev *pdev)
+{
+       /* the uart1 and uart2 interrupt in PIC is enabled as default */
+       pci_write_config_dword(pdev, PCI_UART1_INT_REG, 1);
+       pci_write_config_dword(pdev, PCI_UART2_INT_REG, 1);
+}
+
+static void __init loongson_cs5536_ide_fixup(struct pci_dev *pdev)
+{
+       /* setting the mutex pin as IDE function */
+       pci_write_config_dword(pdev, PCI_IDE_CFG_REG,
+                              CS5536_IDE_FLASH_SIGNATURE);
+}
+
+static void __init loongson_cs5536_acc_fixup(struct pci_dev *pdev)
+{
+       /* enable the AUDIO interrupt in PIC  */
+       pci_write_config_dword(pdev, PCI_ACC_INT_REG, 1);
+
+       pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xc0);
+}
+
+static void __init loongson_cs5536_ohci_fixup(struct pci_dev *pdev)
+{
+       /* enable the OHCI interrupt in PIC */
+       /* THE OHCI, EHCI, UDC, OTG are shared with interrupt in PIC */
+       pci_write_config_dword(pdev, PCI_OHCI_INT_REG, 1);
+}
+
+static void __init loongson_cs5536_ehci_fixup(struct pci_dev *pdev)
+{
+       u32 hi, lo;
+
+       /* Serial short detect enable */
+       _rdmsr(USB_MSR_REG(USB_CONFIG), &hi, &lo);
+       _wrmsr(USB_MSR_REG(USB_CONFIG), (1 << 1) | (1 << 2) | (1 << 3), lo);
+
+       /* setting the USB2.0 micro frame length */
+       pci_write_config_dword(pdev, PCI_EHCI_FLADJ_REG, 0x2000);
+}
+
+static void __init loongson_nec_fixup(struct pci_dev *pdev)
+{
+       unsigned int val;
+
+       pci_read_config_dword(pdev, 0xe0, &val);
+       /* Only 2 port be used */
+       pci_write_config_dword(pdev, 0xe0, (val & ~3) | 0x2);
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA,
+                        loongson_cs5536_isa_fixup);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_OHC,
+                        loongson_cs5536_ohci_fixup);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_EHC,
+                        loongson_cs5536_ehci_fixup);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO,
+                        loongson_cs5536_acc_fixup);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE,
+                        loongson_cs5536_ide_fixup);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB,
+                        loongson_nec_fixup);
similarity index 70%
rename from arch/mips/pci/ops-fuloong2e.c
rename to arch/mips/pci/ops-loongson2.c
index 171f65c..aa5d3da 100644 (file)
 
 #include <loongson.h>
 
+#ifdef CONFIG_CS5536
+#include <cs5536/cs5536_pci.h>
+#include <cs5536/cs5536.h>
+#endif
+
 #define PCI_ACCESS_READ  0
 #define PCI_ACCESS_WRITE 1
 
@@ -43,6 +48,29 @@ static int loongson_pcibios_config_access(unsigned char access_type,
        int reg = where & ~3;
 
        if (busnum == 0) {
+               /* board-specific part,currently,only fuloong2f,yeeloong2f
+                * use CS5536, fuloong2e use via686b, gdium has no
+                * south bridge
+                */
+#ifdef CONFIG_CS5536
+               /* cs5536_pci_conf_read4/write4() will call _rdmsr/_wrmsr() to
+                * access the regsters PCI_MSR_ADDR, PCI_MSR_DATA_LO,
+                * PCI_MSR_DATA_HI, which is bigger than PCI_MSR_CTRL, so, it
+                * will not go this branch, but the others. so, no calling dead
+                * loop here.
+                */
+               if ((PCI_IDSEL_CS5536 == device) && (reg < PCI_MSR_CTRL)) {
+                       switch (access_type) {
+                       case PCI_ACCESS_READ:
+                               *data = cs5536_pci_conf_read4(function, reg);
+                               break;
+                       case PCI_ACCESS_WRITE:
+                               cs5536_pci_conf_write4(function, reg, *data);
+                               break;
+                       }
+                       return 0;
+               }
+#endif
                /* Type 0 configuration for onboard PCI bus */
                if (device > MAX_DEV_NUM)
                        return -1;
@@ -152,3 +180,29 @@ struct pci_ops loongson_pci_ops = {
        .read = loongson_pcibios_read,
        .write = loongson_pcibios_write
 };
+
+#ifdef CONFIG_CS5536
+void _rdmsr(u32 msr, u32 *hi, u32 *lo)
+{
+       struct pci_bus bus = {
+               .number = PCI_BUS_CS5536
+       };
+       u32 devfn = PCI_DEVFN(PCI_IDSEL_CS5536, 0);
+       loongson_pcibios_write(&bus, devfn, PCI_MSR_ADDR, 4, msr);
+       loongson_pcibios_read(&bus, devfn, PCI_MSR_DATA_LO, 4, lo);
+       loongson_pcibios_read(&bus, devfn, PCI_MSR_DATA_HI, 4, hi);
+}
+EXPORT_SYMBOL(_rdmsr);
+
+void _wrmsr(u32 msr, u32 hi, u32 lo)
+{
+       struct pci_bus bus = {
+               .number = PCI_BUS_CS5536
+       };
+       u32 devfn = PCI_DEVFN(PCI_IDSEL_CS5536, 0);
+       loongson_pcibios_write(&bus, devfn, PCI_MSR_ADDR, 4, msr);
+       loongson_pcibios_write(&bus, devfn, PCI_MSR_DATA_LO, 4, lo);
+       loongson_pcibios_write(&bus, devfn, PCI_MSR_DATA_HI, 4, hi);
+}
+EXPORT_SYMBOL(_wrmsr);
+#endif