Skip to content

Commit

Permalink
MIPS: Lemote 2F: Add PCI support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Wu Zhangjin authored and Ralf Baechle committed Dec 17, 2009
1 parent 22c2100 commit 1032bce
Show file tree
Hide file tree
Showing 3 changed files with 216 additions and 1 deletion.
3 changes: 2 additions & 1 deletion arch/mips/pci/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
160 changes: 160 additions & 0 deletions arch/mips/pci/fixup-lemote2f.c
Original file line number Diff line number Diff line change
@@ -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);
54 changes: 54 additions & 0 deletions arch/mips/pci/ops-fuloong2e.c → arch/mips/pci/ops-loongson2.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@

#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

Expand All @@ -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;
Expand Down Expand Up @@ -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

0 comments on commit 1032bce

Please sign in to comment.