diff options
Diffstat (limited to 'arch/mips/pci/pci-ocelot-c.c')
-rw-r--r-- | arch/mips/pci/pci-ocelot-c.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/arch/mips/pci/pci-ocelot-c.c b/arch/mips/pci/pci-ocelot-c.c new file mode 100644 index 000000000000..1d84d36e034d --- /dev/null +++ b/arch/mips/pci/pci-ocelot-c.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/pci.h> | ||
11 | #include <asm/mv64340.h> | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | |||
15 | /* | ||
16 | * We assume the address ranges have already been setup appropriately by | ||
17 | * the firmware. PMON in case of the Ocelot C does that. | ||
18 | */ | ||
19 | static struct resource mv_pci_io_mem0_resource = { | ||
20 | .name = "MV64340 PCI0 IO MEM", | ||
21 | .flags = IORESOURCE_IO | ||
22 | }; | ||
23 | |||
24 | static struct resource mv_pci_mem0_resource = { | ||
25 | .name = "MV64340 PCI0 MEM", | ||
26 | .flags = IORESOURCE_MEM | ||
27 | }; | ||
28 | |||
29 | static struct mv_pci_controller mv_bus0_controller = { | ||
30 | .pcic = { | ||
31 | .pci_ops = &mv_pci_ops, | ||
32 | .mem_resource = &mv_pci_mem0_resource, | ||
33 | .io_resource = &mv_pci_io_mem0_resource, | ||
34 | }, | ||
35 | .config_addr = MV64340_PCI_0_CONFIG_ADDR, | ||
36 | .config_vreg = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG, | ||
37 | }; | ||
38 | |||
39 | static uint32_t mv_io_base, mv_io_size; | ||
40 | |||
41 | static void mv64340_pci0_init(void) | ||
42 | { | ||
43 | uint32_t mem0_base, mem0_size; | ||
44 | uint32_t io_base, io_size; | ||
45 | |||
46 | io_base = MV_READ(MV64340_PCI_0_IO_BASE_ADDR) << 16; | ||
47 | io_size = (MV_READ(MV64340_PCI_0_IO_SIZE) + 1) << 16; | ||
48 | mem0_base = MV_READ(MV64340_PCI_0_MEMORY0_BASE_ADDR) << 16; | ||
49 | mem0_size = (MV_READ(MV64340_PCI_0_MEMORY0_SIZE) + 1) << 16; | ||
50 | |||
51 | mv_pci_io_mem0_resource.start = 0; | ||
52 | mv_pci_io_mem0_resource.end = io_size - 1; | ||
53 | mv_pci_mem0_resource.start = mem0_base; | ||
54 | mv_pci_mem0_resource.end = mem0_base + mem0_size - 1; | ||
55 | mv_bus0_controller.pcic.mem_offset = mem0_base; | ||
56 | mv_bus0_controller.pcic.io_offset = 0; | ||
57 | |||
58 | ioport_resource.end = io_size - 1; | ||
59 | |||
60 | register_pci_controller(&mv_bus0_controller.pcic); | ||
61 | |||
62 | mv_io_base = io_base; | ||
63 | mv_io_size = io_size; | ||
64 | } | ||
65 | |||
66 | static struct resource mv_pci_io_mem1_resource = { | ||
67 | .name = "MV64340 PCI1 IO MEM", | ||
68 | .flags = IORESOURCE_IO | ||
69 | }; | ||
70 | |||
71 | static struct resource mv_pci_mem1_resource = { | ||
72 | .name = "MV64340 PCI1 MEM", | ||
73 | .flags = IORESOURCE_MEM | ||
74 | }; | ||
75 | |||
76 | static struct mv_pci_controller mv_bus1_controller = { | ||
77 | .pcic = { | ||
78 | .pci_ops = &mv_pci_ops, | ||
79 | .mem_resource = &mv_pci_mem1_resource, | ||
80 | .io_resource = &mv_pci_io_mem1_resource, | ||
81 | }, | ||
82 | .config_addr = MV64340_PCI_1_CONFIG_ADDR, | ||
83 | .config_vreg = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG, | ||
84 | }; | ||
85 | |||
86 | static __init void mv64340_pci1_init(void) | ||
87 | { | ||
88 | uint32_t mem0_base, mem0_size; | ||
89 | uint32_t io_base, io_size; | ||
90 | |||
91 | io_base = MV_READ(MV64340_PCI_1_IO_BASE_ADDR) << 16; | ||
92 | io_size = (MV_READ(MV64340_PCI_1_IO_SIZE) + 1) << 16; | ||
93 | mem0_base = MV_READ(MV64340_PCI_1_MEMORY0_BASE_ADDR) << 16; | ||
94 | mem0_size = (MV_READ(MV64340_PCI_1_MEMORY0_SIZE) + 1) << 16; | ||
95 | |||
96 | /* | ||
97 | * Here we assume the I/O window of second bus to be contiguous with | ||
98 | * the first. A gap is no problem but would waste address space for | ||
99 | * remapping the port space. | ||
100 | */ | ||
101 | mv_pci_io_mem1_resource.start = mv_io_size; | ||
102 | mv_pci_io_mem1_resource.end = mv_io_size + io_size - 1; | ||
103 | mv_pci_mem1_resource.start = mem0_base; | ||
104 | mv_pci_mem1_resource.end = mem0_base + mem0_size - 1; | ||
105 | mv_bus1_controller.pcic.mem_offset = mem0_base; | ||
106 | mv_bus1_controller.pcic.io_offset = 0; | ||
107 | |||
108 | ioport_resource.end = io_base + io_size -mv_io_base - 1; | ||
109 | |||
110 | register_pci_controller(&mv_bus1_controller.pcic); | ||
111 | |||
112 | mv_io_size = io_base + io_size - mv_io_base; | ||
113 | } | ||
114 | |||
115 | static __init int __init ocelot_c_pci_init(void) | ||
116 | { | ||
117 | unsigned long io_v_base; | ||
118 | uint32_t enable; | ||
119 | |||
120 | enable = ~MV_READ(MV64340_BASE_ADDR_ENABLE); | ||
121 | |||
122 | /* | ||
123 | * We require at least one enabled I/O or PCI memory window or we | ||
124 | * will ignore this PCI bus. We ignore PCI windows 1, 2 and 3. | ||
125 | */ | ||
126 | if (enable & (0x01 << 9) || enable & (0x01 << 10)) | ||
127 | mv64340_pci0_init(); | ||
128 | |||
129 | if (enable & (0x01 << 14) || enable & (0x01 << 15)) | ||
130 | mv64340_pci1_init(); | ||
131 | |||
132 | if (mv_io_size) { | ||
133 | io_v_base = (unsigned long) ioremap(mv_io_base, mv_io_size); | ||
134 | if (!io_v_base) | ||
135 | panic("Could not ioremap I/O port range"); | ||
136 | |||
137 | set_io_port_base(io_v_base); | ||
138 | } | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | arch_initcall(ocelot_c_pci_init); | ||