]>
Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1032bce3 WZ |
2 | /* |
3 | * Copyright (C) 2008 Lemote Technology | |
4 | * Copyright (C) 2004 ICT CAS | |
5 | * Author: Li xiaoyu, lixy@ict.ac.cn | |
6 | * | |
7 | * Copyright (C) 2007 Lemote, Inc. | |
8 | * Author: Fuxin Zhang, zhangfx@lemote.com | |
1032bce3 WZ |
9 | */ |
10 | #include <linux/init.h> | |
11 | #include <linux/pci.h> | |
12 | ||
13 | #include <loongson.h> | |
14 | #include <cs5536/cs5536.h> | |
15 | #include <cs5536/cs5536_pci.h> | |
16 | ||
17 | /* PCI interrupt pins | |
18 | * | |
19 | * These should not be changed, or you should consider loongson2f interrupt | |
20 | * register and your pci card dispatch | |
21 | */ | |
22 | ||
23 | #define PCIA 4 | |
24 | #define PCIB 5 | |
25 | #define PCIC 6 | |
26 | #define PCID 7 | |
27 | ||
28 | /* all the pci device has the PCIA pin, check the datasheet. */ | |
19a8d6b7 | 29 | static char irq_tab[][5] = { |
70342287 | 30 | /* INTA INTB INTC INTD */ |
1032bce3 WZ |
31 | {0, 0, 0, 0, 0}, /* 11: Unused */ |
32 | {0, 0, 0, 0, 0}, /* 12: Unused */ | |
33 | {0, 0, 0, 0, 0}, /* 13: Unused */ | |
34 | {0, 0, 0, 0, 0}, /* 14: Unused */ | |
35 | {0, 0, 0, 0, 0}, /* 15: Unused */ | |
36 | {0, 0, 0, 0, 0}, /* 16: Unused */ | |
37 | {0, PCIA, 0, 0, 0}, /* 17: RTL8110-0 */ | |
38 | {0, PCIB, 0, 0, 0}, /* 18: RTL8110-1 */ | |
39 | {0, PCIC, 0, 0, 0}, /* 19: SiI3114 */ | |
40 | {0, PCID, 0, 0, 0}, /* 20: 3-ports nec usb */ | |
41 | {0, PCIA, PCIB, PCIC, PCID}, /* 21: PCI-SLOT */ | |
42 | {0, 0, 0, 0, 0}, /* 22: Unused */ | |
43 | {0, 0, 0, 0, 0}, /* 23: Unused */ | |
44 | {0, 0, 0, 0, 0}, /* 24: Unused */ | |
45 | {0, 0, 0, 0, 0}, /* 25: Unused */ | |
46 | {0, 0, 0, 0, 0}, /* 26: Unused */ | |
47 | {0, 0, 0, 0, 0}, /* 27: Unused */ | |
48 | }; | |
49 | ||
19a8d6b7 | 50 | int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) |
1032bce3 WZ |
51 | { |
52 | int virq; | |
53 | ||
54 | if ((PCI_SLOT(dev->devfn) != PCI_IDSEL_CS5536) | |
55 | && (PCI_SLOT(dev->devfn) < 32)) { | |
56 | virq = irq_tab[slot][pin]; | |
57 | printk(KERN_INFO "slot: %d, pin: %d, irq: %d\n", slot, pin, | |
58 | virq + LOONGSON_IRQ_BASE); | |
59 | if (virq != 0) | |
60 | return LOONGSON_IRQ_BASE + virq; | |
61 | else | |
62 | return 0; | |
63 | } else if (PCI_SLOT(dev->devfn) == PCI_IDSEL_CS5536) { /* cs5536 */ | |
64 | switch (PCI_FUNC(dev->devfn)) { | |
65 | case 2: | |
66 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, | |
67 | CS5536_IDE_INTR); | |
70342287 | 68 | return CS5536_IDE_INTR; /* for IDE */ |
1032bce3 WZ |
69 | case 3: |
70 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, | |
71 | CS5536_ACC_INTR); | |
70342287 RB |
72 | return CS5536_ACC_INTR; /* for AUDIO */ |
73 | case 4: /* for OHCI */ | |
74 | case 5: /* for EHCI */ | |
75 | case 6: /* for UDC */ | |
76 | case 7: /* for OTG */ | |
1032bce3 WZ |
77 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, |
78 | CS5536_USB_INTR); | |
79 | return CS5536_USB_INTR; | |
80 | } | |
81 | return dev->irq; | |
82 | } else { | |
83 | printk(KERN_INFO " strange pci slot number.\n"); | |
84 | return 0; | |
85 | } | |
86 | } | |
87 | ||
88 | /* Do platform specific device initialization at pci_enable_device() time */ | |
89 | int pcibios_plat_dev_init(struct pci_dev *dev) | |
90 | { | |
91 | return 0; | |
92 | } | |
93 | ||
94 | /* CS5536 SPEC. fixup */ | |
28eb0e46 | 95 | static void loongson_cs5536_isa_fixup(struct pci_dev *pdev) |
1032bce3 WZ |
96 | { |
97 | /* the uart1 and uart2 interrupt in PIC is enabled as default */ | |
98 | pci_write_config_dword(pdev, PCI_UART1_INT_REG, 1); | |
99 | pci_write_config_dword(pdev, PCI_UART2_INT_REG, 1); | |
100 | } | |
101 | ||
28eb0e46 | 102 | static void loongson_cs5536_ide_fixup(struct pci_dev *pdev) |
1032bce3 WZ |
103 | { |
104 | /* setting the mutex pin as IDE function */ | |
105 | pci_write_config_dword(pdev, PCI_IDE_CFG_REG, | |
106 | CS5536_IDE_FLASH_SIGNATURE); | |
107 | } | |
108 | ||
28eb0e46 | 109 | static void loongson_cs5536_acc_fixup(struct pci_dev *pdev) |
1032bce3 WZ |
110 | { |
111 | /* enable the AUDIO interrupt in PIC */ | |
112 | pci_write_config_dword(pdev, PCI_ACC_INT_REG, 1); | |
113 | ||
114 | pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xc0); | |
115 | } | |
116 | ||
28eb0e46 | 117 | static void loongson_cs5536_ohci_fixup(struct pci_dev *pdev) |
1032bce3 WZ |
118 | { |
119 | /* enable the OHCI interrupt in PIC */ | |
120 | /* THE OHCI, EHCI, UDC, OTG are shared with interrupt in PIC */ | |
121 | pci_write_config_dword(pdev, PCI_OHCI_INT_REG, 1); | |
122 | } | |
123 | ||
28eb0e46 | 124 | static void loongson_cs5536_ehci_fixup(struct pci_dev *pdev) |
1032bce3 WZ |
125 | { |
126 | u32 hi, lo; | |
127 | ||
128 | /* Serial short detect enable */ | |
129 | _rdmsr(USB_MSR_REG(USB_CONFIG), &hi, &lo); | |
c70798f1 | 130 | _wrmsr(USB_MSR_REG(USB_CONFIG), (1 << 1) | (1 << 3), lo); |
1032bce3 WZ |
131 | |
132 | /* setting the USB2.0 micro frame length */ | |
133 | pci_write_config_dword(pdev, PCI_EHCI_FLADJ_REG, 0x2000); | |
134 | } | |
135 | ||
28eb0e46 | 136 | static void loongson_nec_fixup(struct pci_dev *pdev) |
1032bce3 WZ |
137 | { |
138 | unsigned int val; | |
139 | ||
140 | pci_read_config_dword(pdev, 0xe0, &val); | |
141 | /* Only 2 port be used */ | |
142 | pci_write_config_dword(pdev, 0xe0, (val & ~3) | 0x2); | |
143 | } | |
144 | ||
145 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, | |
146 | loongson_cs5536_isa_fixup); | |
147 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_OHC, | |
148 | loongson_cs5536_ohci_fixup); | |
149 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_EHC, | |
150 | loongson_cs5536_ehci_fixup); | |
151 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO, | |
152 | loongson_cs5536_acc_fixup); | |
153 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, | |
154 | loongson_cs5536_ide_fixup); | |
155 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB, | |
156 | loongson_nec_fixup); |