diff options
-rw-r--r-- | Documentation/devicetree/bindings/pci/mvebu-pci.txt | 220 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/Kconfig | 2 | ||||
-rw-r--r-- | drivers/clk/mvebu/clk-gating-ctrl.c | 18 | ||||
-rw-r--r-- | drivers/of/address.c | 67 | ||||
-rw-r--r-- | drivers/of/of_pci.c | 59 | ||||
-rw-r--r-- | drivers/pci/Kconfig | 2 | ||||
-rw-r--r-- | drivers/pci/Makefile | 3 | ||||
-rw-r--r-- | drivers/pci/host/Kconfig | 8 | ||||
-rw-r--r-- | drivers/pci/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/pci/host/pci-mvebu.c | 880 | ||||
-rw-r--r-- | include/linux/of_address.h | 48 | ||||
-rw-r--r-- | include/linux/of_pci.h | 2 |
12 files changed, 1299 insertions, 11 deletions
diff --git a/Documentation/devicetree/bindings/pci/mvebu-pci.txt b/Documentation/devicetree/bindings/pci/mvebu-pci.txt new file mode 100644 index 000000000000..eb69d92c23e1 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/mvebu-pci.txt | |||
@@ -0,0 +1,220 @@ | |||
1 | * Marvell EBU PCIe interfaces | ||
2 | |||
3 | Mandatory properties: | ||
4 | - compatible: one of the following values: | ||
5 | marvell,armada-370-pcie | ||
6 | marvell,armada-xp-pcie | ||
7 | - #address-cells, set to <3> | ||
8 | - #size-cells, set to <2> | ||
9 | - #interrupt-cells, set to <1> | ||
10 | - bus-range: PCI bus numbers covered | ||
11 | - device_type, set to "pci" | ||
12 | - ranges: ranges for the PCI memory and I/O regions, as well as the | ||
13 | MMIO registers to control the PCIe interfaces. | ||
14 | |||
15 | In addition, the Device Tree node must have sub-nodes describing each | ||
16 | PCIe interface, having the following mandatory properties: | ||
17 | - reg: used only for interrupt mapping, so only the first four bytes | ||
18 | are used to refer to the correct bus number and device number. | ||
19 | - assigned-addresses: reference to the MMIO registers used to control | ||
20 | this PCIe interface. | ||
21 | - clocks: the clock associated to this PCIe interface | ||
22 | - marvell,pcie-port: the physical PCIe port number | ||
23 | - status: either "disabled" or "okay" | ||
24 | - device_type, set to "pci" | ||
25 | - #address-cells, set to <3> | ||
26 | - #size-cells, set to <2> | ||
27 | - #interrupt-cells, set to <1> | ||
28 | - ranges, empty property. | ||
29 | - interrupt-map-mask and interrupt-map, standard PCI properties to | ||
30 | define the mapping of the PCIe interface to interrupt numbers. | ||
31 | |||
32 | and the following optional properties: | ||
33 | - marvell,pcie-lane: the physical PCIe lane number, for ports having | ||
34 | multiple lanes. If this property is not found, we assume that the | ||
35 | value is 0. | ||
36 | |||
37 | Example: | ||
38 | |||
39 | pcie-controller { | ||
40 | compatible = "marvell,armada-xp-pcie"; | ||
41 | status = "disabled"; | ||
42 | device_type = "pci"; | ||
43 | |||
44 | #address-cells = <3>; | ||
45 | #size-cells = <2>; | ||
46 | |||
47 | bus-range = <0x00 0xff>; | ||
48 | |||
49 | ranges = <0x82000000 0 0xd0040000 0xd0040000 0 0x00002000 /* Port 0.0 registers */ | ||
50 | 0x82000000 0 0xd0042000 0xd0042000 0 0x00002000 /* Port 2.0 registers */ | ||
51 | 0x82000000 0 0xd0044000 0xd0044000 0 0x00002000 /* Port 0.1 registers */ | ||
52 | 0x82000000 0 0xd0048000 0xd0048000 0 0x00002000 /* Port 0.2 registers */ | ||
53 | 0x82000000 0 0xd004c000 0xd004c000 0 0x00002000 /* Port 0.3 registers */ | ||
54 | 0x82000000 0 0xd0080000 0xd0080000 0 0x00002000 /* Port 1.0 registers */ | ||
55 | 0x82000000 0 0xd0082000 0xd0082000 0 0x00002000 /* Port 3.0 registers */ | ||
56 | 0x82000000 0 0xd0084000 0xd0084000 0 0x00002000 /* Port 1.1 registers */ | ||
57 | 0x82000000 0 0xd0088000 0xd0088000 0 0x00002000 /* Port 1.2 registers */ | ||
58 | 0x82000000 0 0xd008c000 0xd008c000 0 0x00002000 /* Port 1.3 registers */ | ||
59 | 0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */ | ||
60 | 0x81000000 0 0 0xe8000000 0 0x00100000>; /* downstream I/O */ | ||
61 | |||
62 | pcie@1,0 { | ||
63 | device_type = "pci"; | ||
64 | assigned-addresses = <0x82000800 0 0xd0040000 0 0x2000>; | ||
65 | reg = <0x0800 0 0 0 0>; | ||
66 | #address-cells = <3>; | ||
67 | #size-cells = <2>; | ||
68 | #interrupt-cells = <1>; | ||
69 | ranges; | ||
70 | interrupt-map-mask = <0 0 0 0>; | ||
71 | interrupt-map = <0 0 0 0 &mpic 58>; | ||
72 | marvell,pcie-port = <0>; | ||
73 | marvell,pcie-lane = <0>; | ||
74 | clocks = <&gateclk 5>; | ||
75 | status = "disabled"; | ||
76 | }; | ||
77 | |||
78 | pcie@2,0 { | ||
79 | device_type = "pci"; | ||
80 | assigned-addresses = <0x82001000 0 0xd0044000 0 0x2000>; | ||
81 | reg = <0x1000 0 0 0 0>; | ||
82 | #address-cells = <3>; | ||
83 | #size-cells = <2>; | ||
84 | #interrupt-cells = <1>; | ||
85 | ranges; | ||
86 | interrupt-map-mask = <0 0 0 0>; | ||
87 | interrupt-map = <0 0 0 0 &mpic 59>; | ||
88 | marvell,pcie-port = <0>; | ||
89 | marvell,pcie-lane = <1>; | ||
90 | clocks = <&gateclk 6>; | ||
91 | status = "disabled"; | ||
92 | }; | ||
93 | |||
94 | pcie@3,0 { | ||
95 | device_type = "pci"; | ||
96 | assigned-addresses = <0x82001800 0 0xd0048000 0 0x2000>; | ||
97 | reg = <0x1800 0 0 0 0>; | ||
98 | #address-cells = <3>; | ||
99 | #size-cells = <2>; | ||
100 | #interrupt-cells = <1>; | ||
101 | ranges; | ||
102 | interrupt-map-mask = <0 0 0 0>; | ||
103 | interrupt-map = <0 0 0 0 &mpic 60>; | ||
104 | marvell,pcie-port = <0>; | ||
105 | marvell,pcie-lane = <2>; | ||
106 | clocks = <&gateclk 7>; | ||
107 | status = "disabled"; | ||
108 | }; | ||
109 | |||
110 | pcie@4,0 { | ||
111 | device_type = "pci"; | ||
112 | assigned-addresses = <0x82002000 0 0xd004c000 0 0x2000>; | ||
113 | reg = <0x2000 0 0 0 0>; | ||
114 | #address-cells = <3>; | ||
115 | #size-cells = <2>; | ||
116 | #interrupt-cells = <1>; | ||
117 | ranges; | ||
118 | interrupt-map-mask = <0 0 0 0>; | ||
119 | interrupt-map = <0 0 0 0 &mpic 61>; | ||
120 | marvell,pcie-port = <0>; | ||
121 | marvell,pcie-lane = <3>; | ||
122 | clocks = <&gateclk 8>; | ||
123 | status = "disabled"; | ||
124 | }; | ||
125 | |||
126 | pcie@5,0 { | ||
127 | device_type = "pci"; | ||
128 | assigned-addresses = <0x82002800 0 0xd0080000 0 0x2000>; | ||
129 | reg = <0x2800 0 0 0 0>; | ||
130 | #address-cells = <3>; | ||
131 | #size-cells = <2>; | ||
132 | #interrupt-cells = <1>; | ||
133 | ranges; | ||
134 | interrupt-map-mask = <0 0 0 0>; | ||
135 | interrupt-map = <0 0 0 0 &mpic 62>; | ||
136 | marvell,pcie-port = <1>; | ||
137 | marvell,pcie-lane = <0>; | ||
138 | clocks = <&gateclk 9>; | ||
139 | status = "disabled"; | ||
140 | }; | ||
141 | |||
142 | pcie@6,0 { | ||
143 | device_type = "pci"; | ||
144 | assigned-addresses = <0x82003000 0 0xd0084000 0 0x2000>; | ||
145 | reg = <0x3000 0 0 0 0>; | ||
146 | #address-cells = <3>; | ||
147 | #size-cells = <2>; | ||
148 | #interrupt-cells = <1>; | ||
149 | ranges; | ||
150 | interrupt-map-mask = <0 0 0 0>; | ||
151 | interrupt-map = <0 0 0 0 &mpic 63>; | ||
152 | marvell,pcie-port = <1>; | ||
153 | marvell,pcie-lane = <1>; | ||
154 | clocks = <&gateclk 10>; | ||
155 | status = "disabled"; | ||
156 | }; | ||
157 | |||
158 | pcie@7,0 { | ||
159 | device_type = "pci"; | ||
160 | assigned-addresses = <0x82003800 0 0xd0088000 0 0x2000>; | ||
161 | reg = <0x3800 0 0 0 0>; | ||
162 | #address-cells = <3>; | ||
163 | #size-cells = <2>; | ||
164 | #interrupt-cells = <1>; | ||
165 | ranges; | ||
166 | interrupt-map-mask = <0 0 0 0>; | ||
167 | interrupt-map = <0 0 0 0 &mpic 64>; | ||
168 | marvell,pcie-port = <1>; | ||
169 | marvell,pcie-lane = <2>; | ||
170 | clocks = <&gateclk 11>; | ||
171 | status = "disabled"; | ||
172 | }; | ||
173 | |||
174 | pcie@8,0 { | ||
175 | device_type = "pci"; | ||
176 | assigned-addresses = <0x82004000 0 0xd008c000 0 0x2000>; | ||
177 | reg = <0x4000 0 0 0 0>; | ||
178 | #address-cells = <3>; | ||
179 | #size-cells = <2>; | ||
180 | #interrupt-cells = <1>; | ||
181 | ranges; | ||
182 | interrupt-map-mask = <0 0 0 0>; | ||
183 | interrupt-map = <0 0 0 0 &mpic 65>; | ||
184 | marvell,pcie-port = <1>; | ||
185 | marvell,pcie-lane = <3>; | ||
186 | clocks = <&gateclk 12>; | ||
187 | status = "disabled"; | ||
188 | }; | ||
189 | pcie@9,0 { | ||
190 | device_type = "pci"; | ||
191 | assigned-addresses = <0x82004800 0 0xd0042000 0 0x2000>; | ||
192 | reg = <0x4800 0 0 0 0>; | ||
193 | #address-cells = <3>; | ||
194 | #size-cells = <2>; | ||
195 | #interrupt-cells = <1>; | ||
196 | ranges; | ||
197 | interrupt-map-mask = <0 0 0 0>; | ||
198 | interrupt-map = <0 0 0 0 &mpic 99>; | ||
199 | marvell,pcie-port = <2>; | ||
200 | marvell,pcie-lane = <0>; | ||
201 | clocks = <&gateclk 26>; | ||
202 | status = "disabled"; | ||
203 | }; | ||
204 | |||
205 | pcie@10,0 { | ||
206 | device_type = "pci"; | ||
207 | assigned-addresses = <0x82005000 0 0xd0082000 0 0x2000>; | ||
208 | reg = <0x5000 0 0 0 0>; | ||
209 | #address-cells = <3>; | ||
210 | #size-cells = <2>; | ||
211 | #interrupt-cells = <1>; | ||
212 | ranges; | ||
213 | interrupt-map-mask = <0 0 0 0>; | ||
214 | interrupt-map = <0 0 0 0 &mpic 103>; | ||
215 | marvell,pcie-port = <3>; | ||
216 | marvell,pcie-lane = <0>; | ||
217 | clocks = <&gateclk 27>; | ||
218 | status = "disabled"; | ||
219 | }; | ||
220 | }; | ||
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 80a8bcacd9d5..fb827ac9d906 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig | |||
@@ -16,6 +16,8 @@ config ARCH_MVEBU | |||
16 | select MVEBU_MBUS | 16 | select MVEBU_MBUS |
17 | select ZONE_DMA if ARM_LPAE | 17 | select ZONE_DMA if ARM_LPAE |
18 | select ARCH_REQUIRE_GPIOLIB | 18 | select ARCH_REQUIRE_GPIOLIB |
19 | select MIGHT_HAVE_PCI | ||
20 | select PCI_QUIRKS if PCI | ||
19 | 21 | ||
20 | if ARCH_MVEBU | 22 | if ARCH_MVEBU |
21 | 23 | ||
diff --git a/drivers/clk/mvebu/clk-gating-ctrl.c b/drivers/clk/mvebu/clk-gating-ctrl.c index ebf141d4374b..2f037235bdbd 100644 --- a/drivers/clk/mvebu/clk-gating-ctrl.c +++ b/drivers/clk/mvebu/clk-gating-ctrl.c | |||
@@ -119,8 +119,8 @@ static const struct mvebu_soc_descr __initconst armada_370_gating_descr[] = { | |||
119 | { "pex1_en", NULL, 2 }, | 119 | { "pex1_en", NULL, 2 }, |
120 | { "ge1", NULL, 3 }, | 120 | { "ge1", NULL, 3 }, |
121 | { "ge0", NULL, 4 }, | 121 | { "ge0", NULL, 4 }, |
122 | { "pex0", NULL, 5 }, | 122 | { "pex0", "pex0_en", 5 }, |
123 | { "pex1", NULL, 9 }, | 123 | { "pex1", "pex1_en", 9 }, |
124 | { "sata0", NULL, 15 }, | 124 | { "sata0", NULL, 15 }, |
125 | { "sdio", NULL, 17 }, | 125 | { "sdio", NULL, 17 }, |
126 | { "tdm", NULL, 25 }, | 126 | { "tdm", NULL, 25 }, |
@@ -137,10 +137,14 @@ static const struct mvebu_soc_descr __initconst armada_xp_gating_descr[] = { | |||
137 | { "ge2", NULL, 2 }, | 137 | { "ge2", NULL, 2 }, |
138 | { "ge1", NULL, 3 }, | 138 | { "ge1", NULL, 3 }, |
139 | { "ge0", NULL, 4 }, | 139 | { "ge0", NULL, 4 }, |
140 | { "pex0", NULL, 5 }, | 140 | { "pex00", NULL, 5 }, |
141 | { "pex1", NULL, 6 }, | 141 | { "pex01", NULL, 6 }, |
142 | { "pex2", NULL, 7 }, | 142 | { "pex02", NULL, 7 }, |
143 | { "pex3", NULL, 8 }, | 143 | { "pex03", NULL, 8 }, |
144 | { "pex10", NULL, 9 }, | ||
145 | { "pex11", NULL, 10 }, | ||
146 | { "pex12", NULL, 11 }, | ||
147 | { "pex13", NULL, 12 }, | ||
144 | { "bp", NULL, 13 }, | 148 | { "bp", NULL, 13 }, |
145 | { "sata0lnk", NULL, 14 }, | 149 | { "sata0lnk", NULL, 14 }, |
146 | { "sata0", "sata0lnk", 15 }, | 150 | { "sata0", "sata0lnk", 15 }, |
@@ -152,6 +156,8 @@ static const struct mvebu_soc_descr __initconst armada_xp_gating_descr[] = { | |||
152 | { "xor0", NULL, 22 }, | 156 | { "xor0", NULL, 22 }, |
153 | { "crypto", NULL, 23 }, | 157 | { "crypto", NULL, 23 }, |
154 | { "tdm", NULL, 25 }, | 158 | { "tdm", NULL, 25 }, |
159 | { "pex20", NULL, 26 }, | ||
160 | { "pex30", NULL, 27 }, | ||
155 | { "xor1", NULL, 28 }, | 161 | { "xor1", NULL, 28 }, |
156 | { "sata1lnk", NULL, 29 }, | 162 | { "sata1lnk", NULL, 29 }, |
157 | { "sata1", "sata1lnk", 30 }, | 163 | { "sata1", "sata1lnk", 30 }, |
diff --git a/drivers/of/address.c b/drivers/of/address.c index 04da786c84d2..fdd0636a987d 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c | |||
@@ -227,6 +227,73 @@ int of_pci_address_to_resource(struct device_node *dev, int bar, | |||
227 | return __of_address_to_resource(dev, addrp, size, flags, NULL, r); | 227 | return __of_address_to_resource(dev, addrp, size, flags, NULL, r); |
228 | } | 228 | } |
229 | EXPORT_SYMBOL_GPL(of_pci_address_to_resource); | 229 | EXPORT_SYMBOL_GPL(of_pci_address_to_resource); |
230 | |||
231 | int of_pci_range_parser_init(struct of_pci_range_parser *parser, | ||
232 | struct device_node *node) | ||
233 | { | ||
234 | const int na = 3, ns = 2; | ||
235 | int rlen; | ||
236 | |||
237 | parser->node = node; | ||
238 | parser->pna = of_n_addr_cells(node); | ||
239 | parser->np = parser->pna + na + ns; | ||
240 | |||
241 | parser->range = of_get_property(node, "ranges", &rlen); | ||
242 | if (parser->range == NULL) | ||
243 | return -ENOENT; | ||
244 | |||
245 | parser->end = parser->range + rlen / sizeof(__be32); | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | EXPORT_SYMBOL_GPL(of_pci_range_parser_init); | ||
250 | |||
251 | struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, | ||
252 | struct of_pci_range *range) | ||
253 | { | ||
254 | const int na = 3, ns = 2; | ||
255 | |||
256 | if (!range) | ||
257 | return NULL; | ||
258 | |||
259 | if (!parser->range || parser->range + parser->np > parser->end) | ||
260 | return NULL; | ||
261 | |||
262 | range->pci_space = parser->range[0]; | ||
263 | range->flags = of_bus_pci_get_flags(parser->range); | ||
264 | range->pci_addr = of_read_number(parser->range + 1, ns); | ||
265 | range->cpu_addr = of_translate_address(parser->node, | ||
266 | parser->range + na); | ||
267 | range->size = of_read_number(parser->range + parser->pna + na, ns); | ||
268 | |||
269 | parser->range += parser->np; | ||
270 | |||
271 | /* Now consume following elements while they are contiguous */ | ||
272 | while (parser->range + parser->np <= parser->end) { | ||
273 | u32 flags, pci_space; | ||
274 | u64 pci_addr, cpu_addr, size; | ||
275 | |||
276 | pci_space = be32_to_cpup(parser->range); | ||
277 | flags = of_bus_pci_get_flags(parser->range); | ||
278 | pci_addr = of_read_number(parser->range + 1, ns); | ||
279 | cpu_addr = of_translate_address(parser->node, | ||
280 | parser->range + na); | ||
281 | size = of_read_number(parser->range + parser->pna + na, ns); | ||
282 | |||
283 | if (flags != range->flags) | ||
284 | break; | ||
285 | if (pci_addr != range->pci_addr + range->size || | ||
286 | cpu_addr != range->cpu_addr + range->size) | ||
287 | break; | ||
288 | |||
289 | range->size += size; | ||
290 | parser->range += parser->np; | ||
291 | } | ||
292 | |||
293 | return range; | ||
294 | } | ||
295 | EXPORT_SYMBOL_GPL(of_pci_range_parser_one); | ||
296 | |||
230 | #endif /* CONFIG_PCI */ | 297 | #endif /* CONFIG_PCI */ |
231 | 298 | ||
232 | /* | 299 | /* |
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index 13e37e2d8ec1..42c687a820ac 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c | |||
@@ -5,14 +5,15 @@ | |||
5 | #include <asm/prom.h> | 5 | #include <asm/prom.h> |
6 | 6 | ||
7 | static inline int __of_pci_pci_compare(struct device_node *node, | 7 | static inline int __of_pci_pci_compare(struct device_node *node, |
8 | unsigned int devfn) | 8 | unsigned int data) |
9 | { | 9 | { |
10 | unsigned int size; | 10 | int devfn; |
11 | const __be32 *reg = of_get_property(node, "reg", &size); | ||
12 | 11 | ||
13 | if (!reg || size < 5 * sizeof(__be32)) | 12 | devfn = of_pci_get_devfn(node); |
13 | if (devfn < 0) | ||
14 | return 0; | 14 | return 0; |
15 | return ((be32_to_cpup(®[0]) >> 8) & 0xff) == devfn; | 15 | |
16 | return devfn == data; | ||
16 | } | 17 | } |
17 | 18 | ||
18 | struct device_node *of_pci_find_child_device(struct device_node *parent, | 19 | struct device_node *of_pci_find_child_device(struct device_node *parent, |
@@ -40,3 +41,51 @@ struct device_node *of_pci_find_child_device(struct device_node *parent, | |||
40 | return NULL; | 41 | return NULL; |
41 | } | 42 | } |
42 | EXPORT_SYMBOL_GPL(of_pci_find_child_device); | 43 | EXPORT_SYMBOL_GPL(of_pci_find_child_device); |
44 | |||
45 | /** | ||
46 | * of_pci_get_devfn() - Get device and function numbers for a device node | ||
47 | * @np: device node | ||
48 | * | ||
49 | * Parses a standard 5-cell PCI resource and returns an 8-bit value that can | ||
50 | * be passed to the PCI_SLOT() and PCI_FUNC() macros to extract the device | ||
51 | * and function numbers respectively. On error a negative error code is | ||
52 | * returned. | ||
53 | */ | ||
54 | int of_pci_get_devfn(struct device_node *np) | ||
55 | { | ||
56 | unsigned int size; | ||
57 | const __be32 *reg; | ||
58 | |||
59 | reg = of_get_property(np, "reg", &size); | ||
60 | |||
61 | if (!reg || size < 5 * sizeof(__be32)) | ||
62 | return -EINVAL; | ||
63 | |||
64 | return (be32_to_cpup(reg) >> 8) & 0xff; | ||
65 | } | ||
66 | EXPORT_SYMBOL_GPL(of_pci_get_devfn); | ||
67 | |||
68 | /** | ||
69 | * of_pci_parse_bus_range() - parse the bus-range property of a PCI device | ||
70 | * @node: device node | ||
71 | * @res: address to a struct resource to return the bus-range | ||
72 | * | ||
73 | * Returns 0 on success or a negative error-code on failure. | ||
74 | */ | ||
75 | int of_pci_parse_bus_range(struct device_node *node, struct resource *res) | ||
76 | { | ||
77 | const __be32 *values; | ||
78 | int len; | ||
79 | |||
80 | values = of_get_property(node, "bus-range", &len); | ||
81 | if (!values || len < sizeof(*values) * 2) | ||
82 | return -EINVAL; | ||
83 | |||
84 | res->name = node->name; | ||
85 | res->start = be32_to_cpup(values++); | ||
86 | res->end = be32_to_cpup(values); | ||
87 | res->flags = IORESOURCE_BUS; | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | EXPORT_SYMBOL_GPL(of_pci_parse_bus_range); | ||
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 6d51aa68ec7a..ac45398ebb8e 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig | |||
@@ -119,3 +119,5 @@ config PCI_IOAPIC | |||
119 | config PCI_LABEL | 119 | config PCI_LABEL |
120 | def_bool y if (DMI || ACPI) | 120 | def_bool y if (DMI || ACPI) |
121 | select NLS | 121 | select NLS |
122 | |||
123 | source "drivers/pci/host/Kconfig" | ||
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 0c3efcffa83b..6ebf5bf8e7a7 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile | |||
@@ -67,3 +67,6 @@ obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o | |||
67 | obj-$(CONFIG_OF) += of.o | 67 | obj-$(CONFIG_OF) += of.o |
68 | 68 | ||
69 | ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG | 69 | ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG |
70 | |||
71 | # PCI host controller drivers | ||
72 | obj-y += host/ | ||
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig new file mode 100644 index 000000000000..6918fbc92c02 --- /dev/null +++ b/drivers/pci/host/Kconfig | |||
@@ -0,0 +1,8 @@ | |||
1 | menu "PCI host controller drivers" | ||
2 | depends on PCI | ||
3 | |||
4 | config PCI_MVEBU | ||
5 | bool "Marvell EBU PCIe controller" | ||
6 | depends on ARCH_MVEBU | ||
7 | |||
8 | endmenu | ||
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile new file mode 100644 index 000000000000..5ea2d8bf013a --- /dev/null +++ b/drivers/pci/host/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o | |||
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c new file mode 100644 index 000000000000..9236ac0bd17b --- /dev/null +++ b/drivers/pci/host/pci-mvebu.c | |||
@@ -0,0 +1,880 @@ | |||
1 | /* | ||
2 | * PCIe driver for Marvell Armada 370 and Armada XP SoCs | ||
3 | * | ||
4 | * This file is licensed under the terms of the GNU General Public | ||
5 | * License version 2. This program is licensed "as is" without any | ||
6 | * warranty of any kind, whether express or implied. | ||
7 | */ | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/pci.h> | ||
11 | #include <linux/clk.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/mbus.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/of_address.h> | ||
17 | #include <linux/of_pci.h> | ||
18 | #include <linux/of_irq.h> | ||
19 | #include <linux/of_platform.h> | ||
20 | |||
21 | /* | ||
22 | * PCIe unit register offsets. | ||
23 | */ | ||
24 | #define PCIE_DEV_ID_OFF 0x0000 | ||
25 | #define PCIE_CMD_OFF 0x0004 | ||
26 | #define PCIE_DEV_REV_OFF 0x0008 | ||
27 | #define PCIE_BAR_LO_OFF(n) (0x0010 + ((n) << 3)) | ||
28 | #define PCIE_BAR_HI_OFF(n) (0x0014 + ((n) << 3)) | ||
29 | #define PCIE_HEADER_LOG_4_OFF 0x0128 | ||
30 | #define PCIE_BAR_CTRL_OFF(n) (0x1804 + (((n) - 1) * 4)) | ||
31 | #define PCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4)) | ||
32 | #define PCIE_WIN04_BASE_OFF(n) (0x1824 + ((n) << 4)) | ||
33 | #define PCIE_WIN04_REMAP_OFF(n) (0x182c + ((n) << 4)) | ||
34 | #define PCIE_WIN5_CTRL_OFF 0x1880 | ||
35 | #define PCIE_WIN5_BASE_OFF 0x1884 | ||
36 | #define PCIE_WIN5_REMAP_OFF 0x188c | ||
37 | #define PCIE_CONF_ADDR_OFF 0x18f8 | ||
38 | #define PCIE_CONF_ADDR_EN 0x80000000 | ||
39 | #define PCIE_CONF_REG(r) ((((r) & 0xf00) << 16) | ((r) & 0xfc)) | ||
40 | #define PCIE_CONF_BUS(b) (((b) & 0xff) << 16) | ||
41 | #define PCIE_CONF_DEV(d) (((d) & 0x1f) << 11) | ||
42 | #define PCIE_CONF_FUNC(f) (((f) & 0x7) << 8) | ||
43 | #define PCIE_CONF_ADDR(bus, devfn, where) \ | ||
44 | (PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn)) | \ | ||
45 | PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where) | \ | ||
46 | PCIE_CONF_ADDR_EN) | ||
47 | #define PCIE_CONF_DATA_OFF 0x18fc | ||
48 | #define PCIE_MASK_OFF 0x1910 | ||
49 | #define PCIE_MASK_ENABLE_INTS 0x0f000000 | ||
50 | #define PCIE_CTRL_OFF 0x1a00 | ||
51 | #define PCIE_CTRL_X1_MODE 0x0001 | ||
52 | #define PCIE_STAT_OFF 0x1a04 | ||
53 | #define PCIE_STAT_BUS 0xff00 | ||
54 | #define PCIE_STAT_LINK_DOWN BIT(0) | ||
55 | #define PCIE_DEBUG_CTRL 0x1a60 | ||
56 | #define PCIE_DEBUG_SOFT_RESET BIT(20) | ||
57 | |||
58 | /* | ||
59 | * This product ID is registered by Marvell, and used when the Marvell | ||
60 | * SoC is not the root complex, but an endpoint on the PCIe bus. It is | ||
61 | * therefore safe to re-use this PCI ID for our emulated PCI-to-PCI | ||
62 | * bridge. | ||
63 | */ | ||
64 | #define MARVELL_EMULATED_PCI_PCI_BRIDGE_ID 0x7846 | ||
65 | |||
66 | /* PCI configuration space of a PCI-to-PCI bridge */ | ||
67 | struct mvebu_sw_pci_bridge { | ||
68 | u16 vendor; | ||
69 | u16 device; | ||
70 | u16 command; | ||
71 | u16 status; | ||
72 | u16 class; | ||
73 | u8 interface; | ||
74 | u8 revision; | ||
75 | u8 bist; | ||
76 | u8 header_type; | ||
77 | u8 latency_timer; | ||
78 | u8 cache_line_size; | ||
79 | u32 bar[2]; | ||
80 | u8 primary_bus; | ||
81 | u8 secondary_bus; | ||
82 | u8 subordinate_bus; | ||
83 | u8 secondary_latency_timer; | ||
84 | u8 iobase; | ||
85 | u8 iolimit; | ||
86 | u16 secondary_status; | ||
87 | u16 membase; | ||
88 | u16 memlimit; | ||
89 | u16 prefmembase; | ||
90 | u16 prefmemlimit; | ||
91 | u32 prefbaseupper; | ||
92 | u32 preflimitupper; | ||
93 | u16 iobaseupper; | ||
94 | u16 iolimitupper; | ||
95 | u8 cappointer; | ||
96 | u8 reserved1; | ||
97 | u16 reserved2; | ||
98 | u32 romaddr; | ||
99 | u8 intline; | ||
100 | u8 intpin; | ||
101 | u16 bridgectrl; | ||
102 | }; | ||
103 | |||
104 | struct mvebu_pcie_port; | ||
105 | |||
106 | /* Structure representing all PCIe interfaces */ | ||
107 | struct mvebu_pcie { | ||
108 | struct platform_device *pdev; | ||
109 | struct mvebu_pcie_port *ports; | ||
110 | struct resource io; | ||
111 | struct resource realio; | ||
112 | struct resource mem; | ||
113 | struct resource busn; | ||
114 | int nports; | ||
115 | }; | ||
116 | |||
117 | /* Structure representing one PCIe interface */ | ||
118 | struct mvebu_pcie_port { | ||
119 | char *name; | ||
120 | void __iomem *base; | ||
121 | spinlock_t conf_lock; | ||
122 | int haslink; | ||
123 | u32 port; | ||
124 | u32 lane; | ||
125 | int devfn; | ||
126 | struct clk *clk; | ||
127 | struct mvebu_sw_pci_bridge bridge; | ||
128 | struct device_node *dn; | ||
129 | struct mvebu_pcie *pcie; | ||
130 | phys_addr_t memwin_base; | ||
131 | size_t memwin_size; | ||
132 | phys_addr_t iowin_base; | ||
133 | size_t iowin_size; | ||
134 | }; | ||
135 | |||
136 | static bool mvebu_pcie_link_up(struct mvebu_pcie_port *port) | ||
137 | { | ||
138 | return !(readl(port->base + PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN); | ||
139 | } | ||
140 | |||
141 | static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie_port *port, int nr) | ||
142 | { | ||
143 | u32 stat; | ||
144 | |||
145 | stat = readl(port->base + PCIE_STAT_OFF); | ||
146 | stat &= ~PCIE_STAT_BUS; | ||
147 | stat |= nr << 8; | ||
148 | writel(stat, port->base + PCIE_STAT_OFF); | ||
149 | } | ||
150 | |||
151 | /* | ||
152 | * Setup PCIE BARs and Address Decode Wins: | ||
153 | * BAR[0,2] -> disabled, BAR[1] -> covers all DRAM banks | ||
154 | * WIN[0-3] -> DRAM bank[0-3] | ||
155 | */ | ||
156 | static void __init mvebu_pcie_setup_wins(struct mvebu_pcie_port *port) | ||
157 | { | ||
158 | const struct mbus_dram_target_info *dram; | ||
159 | u32 size; | ||
160 | int i; | ||
161 | |||
162 | dram = mv_mbus_dram_info(); | ||
163 | |||
164 | /* First, disable and clear BARs and windows. */ | ||
165 | for (i = 1; i < 3; i++) { | ||
166 | writel(0, port->base + PCIE_BAR_CTRL_OFF(i)); | ||
167 | writel(0, port->base + PCIE_BAR_LO_OFF(i)); | ||
168 | writel(0, port->base + PCIE_BAR_HI_OFF(i)); | ||
169 | } | ||
170 | |||
171 | for (i = 0; i < 5; i++) { | ||
172 | writel(0, port->base + PCIE_WIN04_CTRL_OFF(i)); | ||
173 | writel(0, port->base + PCIE_WIN04_BASE_OFF(i)); | ||
174 | writel(0, port->base + PCIE_WIN04_REMAP_OFF(i)); | ||
175 | } | ||
176 | |||
177 | writel(0, port->base + PCIE_WIN5_CTRL_OFF); | ||
178 | writel(0, port->base + PCIE_WIN5_BASE_OFF); | ||
179 | writel(0, port->base + PCIE_WIN5_REMAP_OFF); | ||
180 | |||
181 | /* Setup windows for DDR banks. Count total DDR size on the fly. */ | ||
182 | size = 0; | ||
183 | for (i = 0; i < dram->num_cs; i++) { | ||
184 | const struct mbus_dram_window *cs = dram->cs + i; | ||
185 | |||
186 | writel(cs->base & 0xffff0000, | ||
187 | port->base + PCIE_WIN04_BASE_OFF(i)); | ||
188 | writel(0, port->base + PCIE_WIN04_REMAP_OFF(i)); | ||
189 | writel(((cs->size - 1) & 0xffff0000) | | ||
190 | (cs->mbus_attr << 8) | | ||
191 | (dram->mbus_dram_target_id << 4) | 1, | ||
192 | port->base + PCIE_WIN04_CTRL_OFF(i)); | ||
193 | |||
194 | size += cs->size; | ||
195 | } | ||
196 | |||
197 | /* Round up 'size' to the nearest power of two. */ | ||
198 | if ((size & (size - 1)) != 0) | ||
199 | size = 1 << fls(size); | ||
200 | |||
201 | /* Setup BAR[1] to all DRAM banks. */ | ||
202 | writel(dram->cs[0].base, port->base + PCIE_BAR_LO_OFF(1)); | ||
203 | writel(0, port->base + PCIE_BAR_HI_OFF(1)); | ||
204 | writel(((size - 1) & 0xffff0000) | 1, | ||
205 | port->base + PCIE_BAR_CTRL_OFF(1)); | ||
206 | } | ||
207 | |||
208 | static void __init mvebu_pcie_setup_hw(struct mvebu_pcie_port *port) | ||
209 | { | ||
210 | u16 cmd; | ||
211 | u32 mask; | ||
212 | |||
213 | /* Point PCIe unit MBUS decode windows to DRAM space. */ | ||
214 | mvebu_pcie_setup_wins(port); | ||
215 | |||
216 | /* Master + slave enable. */ | ||
217 | cmd = readw(port->base + PCIE_CMD_OFF); | ||
218 | cmd |= PCI_COMMAND_IO; | ||
219 | cmd |= PCI_COMMAND_MEMORY; | ||
220 | cmd |= PCI_COMMAND_MASTER; | ||
221 | writew(cmd, port->base + PCIE_CMD_OFF); | ||
222 | |||
223 | /* Enable interrupt lines A-D. */ | ||
224 | mask = readl(port->base + PCIE_MASK_OFF); | ||
225 | mask |= PCIE_MASK_ENABLE_INTS; | ||
226 | writel(mask, port->base + PCIE_MASK_OFF); | ||
227 | } | ||
228 | |||
229 | static int mvebu_pcie_hw_rd_conf(struct mvebu_pcie_port *port, | ||
230 | struct pci_bus *bus, | ||
231 | u32 devfn, int where, int size, u32 *val) | ||
232 | { | ||
233 | writel(PCIE_CONF_ADDR(bus->number, devfn, where), | ||
234 | port->base + PCIE_CONF_ADDR_OFF); | ||
235 | |||
236 | *val = readl(port->base + PCIE_CONF_DATA_OFF); | ||
237 | |||
238 | if (size == 1) | ||
239 | *val = (*val >> (8 * (where & 3))) & 0xff; | ||
240 | else if (size == 2) | ||
241 | *val = (*val >> (8 * (where & 3))) & 0xffff; | ||
242 | |||
243 | return PCIBIOS_SUCCESSFUL; | ||
244 | } | ||
245 | |||
246 | static int mvebu_pcie_hw_wr_conf(struct mvebu_pcie_port *port, | ||
247 | struct pci_bus *bus, | ||
248 | u32 devfn, int where, int size, u32 val) | ||
249 | { | ||
250 | int ret = PCIBIOS_SUCCESSFUL; | ||
251 | |||
252 | writel(PCIE_CONF_ADDR(bus->number, devfn, where), | ||
253 | port->base + PCIE_CONF_ADDR_OFF); | ||
254 | |||
255 | if (size == 4) | ||
256 | writel(val, port->base + PCIE_CONF_DATA_OFF); | ||
257 | else if (size == 2) | ||
258 | writew(val, port->base + PCIE_CONF_DATA_OFF + (where & 3)); | ||
259 | else if (size == 1) | ||
260 | writeb(val, port->base + PCIE_CONF_DATA_OFF + (where & 3)); | ||
261 | else | ||
262 | ret = PCIBIOS_BAD_REGISTER_NUMBER; | ||
263 | |||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) | ||
268 | { | ||
269 | phys_addr_t iobase; | ||
270 | |||
271 | /* Are the new iobase/iolimit values invalid? */ | ||
272 | if (port->bridge.iolimit < port->bridge.iobase || | ||
273 | port->bridge.iolimitupper < port->bridge.iobaseupper) { | ||
274 | |||
275 | /* If a window was configured, remove it */ | ||
276 | if (port->iowin_base) { | ||
277 | mvebu_mbus_del_window(port->iowin_base, | ||
278 | port->iowin_size); | ||
279 | port->iowin_base = 0; | ||
280 | port->iowin_size = 0; | ||
281 | } | ||
282 | |||
283 | return; | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * We read the PCI-to-PCI bridge emulated registers, and | ||
288 | * calculate the base address and size of the address decoding | ||
289 | * window to setup, according to the PCI-to-PCI bridge | ||
290 | * specifications. iobase is the bus address, port->iowin_base | ||
291 | * is the CPU address. | ||
292 | */ | ||
293 | iobase = ((port->bridge.iobase & 0xF0) << 8) | | ||
294 | (port->bridge.iobaseupper << 16); | ||
295 | port->iowin_base = port->pcie->io.start + iobase; | ||
296 | port->iowin_size = ((0xFFF | ((port->bridge.iolimit & 0xF0) << 8) | | ||
297 | (port->bridge.iolimitupper << 16)) - | ||
298 | iobase); | ||
299 | |||
300 | mvebu_mbus_add_window_remap_flags(port->name, port->iowin_base, | ||
301 | port->iowin_size, | ||
302 | iobase, | ||
303 | MVEBU_MBUS_PCI_IO); | ||
304 | |||
305 | pci_ioremap_io(iobase, port->iowin_base); | ||
306 | } | ||
307 | |||
308 | static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) | ||
309 | { | ||
310 | /* Are the new membase/memlimit values invalid? */ | ||
311 | if (port->bridge.memlimit < port->bridge.membase) { | ||
312 | |||
313 | /* If a window was configured, remove it */ | ||
314 | if (port->memwin_base) { | ||
315 | mvebu_mbus_del_window(port->memwin_base, | ||
316 | port->memwin_size); | ||
317 | port->memwin_base = 0; | ||
318 | port->memwin_size = 0; | ||
319 | } | ||
320 | |||
321 | return; | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | * We read the PCI-to-PCI bridge emulated registers, and | ||
326 | * calculate the base address and size of the address decoding | ||
327 | * window to setup, according to the PCI-to-PCI bridge | ||
328 | * specifications. | ||
329 | */ | ||
330 | port->memwin_base = ((port->bridge.membase & 0xFFF0) << 16); | ||
331 | port->memwin_size = | ||
332 | (((port->bridge.memlimit & 0xFFF0) << 16) | 0xFFFFF) - | ||
333 | port->memwin_base; | ||
334 | |||
335 | mvebu_mbus_add_window_remap_flags(port->name, port->memwin_base, | ||
336 | port->memwin_size, | ||
337 | MVEBU_MBUS_NO_REMAP, | ||
338 | MVEBU_MBUS_PCI_MEM); | ||
339 | } | ||
340 | |||
341 | /* | ||
342 | * Initialize the configuration space of the PCI-to-PCI bridge | ||
343 | * associated with the given PCIe interface. | ||
344 | */ | ||
345 | static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port) | ||
346 | { | ||
347 | struct mvebu_sw_pci_bridge *bridge = &port->bridge; | ||
348 | |||
349 | memset(bridge, 0, sizeof(struct mvebu_sw_pci_bridge)); | ||
350 | |||
351 | bridge->status = PCI_STATUS_CAP_LIST; | ||
352 | bridge->class = PCI_CLASS_BRIDGE_PCI; | ||
353 | bridge->vendor = PCI_VENDOR_ID_MARVELL; | ||
354 | bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID; | ||
355 | bridge->header_type = PCI_HEADER_TYPE_BRIDGE; | ||
356 | bridge->cache_line_size = 0x10; | ||
357 | |||
358 | /* We support 32 bits I/O addressing */ | ||
359 | bridge->iobase = PCI_IO_RANGE_TYPE_32; | ||
360 | bridge->iolimit = PCI_IO_RANGE_TYPE_32; | ||
361 | } | ||
362 | |||
363 | /* | ||
364 | * Read the configuration space of the PCI-to-PCI bridge associated to | ||
365 | * the given PCIe interface. | ||
366 | */ | ||
367 | static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port, | ||
368 | unsigned int where, int size, u32 *value) | ||
369 | { | ||
370 | struct mvebu_sw_pci_bridge *bridge = &port->bridge; | ||
371 | |||
372 | switch (where & ~3) { | ||
373 | case PCI_VENDOR_ID: | ||
374 | *value = bridge->device << 16 | bridge->vendor; | ||
375 | break; | ||
376 | |||
377 | case PCI_COMMAND: | ||
378 | *value = bridge->status << 16 | bridge->command; | ||
379 | break; | ||
380 | |||
381 | case PCI_CLASS_REVISION: | ||
382 | *value = bridge->class << 16 | bridge->interface << 8 | | ||
383 | bridge->revision; | ||
384 | break; | ||
385 | |||
386 | case PCI_CACHE_LINE_SIZE: | ||
387 | *value = bridge->bist << 24 | bridge->header_type << 16 | | ||
388 | bridge->latency_timer << 8 | bridge->cache_line_size; | ||
389 | break; | ||
390 | |||
391 | case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1: | ||
392 | *value = bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4]; | ||
393 | break; | ||
394 | |||
395 | case PCI_PRIMARY_BUS: | ||
396 | *value = (bridge->secondary_latency_timer << 24 | | ||
397 | bridge->subordinate_bus << 16 | | ||
398 | bridge->secondary_bus << 8 | | ||
399 | bridge->primary_bus); | ||
400 | break; | ||
401 | |||
402 | case PCI_IO_BASE: | ||
403 | *value = (bridge->secondary_status << 16 | | ||
404 | bridge->iolimit << 8 | | ||
405 | bridge->iobase); | ||
406 | break; | ||
407 | |||
408 | case PCI_MEMORY_BASE: | ||
409 | *value = (bridge->memlimit << 16 | bridge->membase); | ||
410 | break; | ||
411 | |||
412 | case PCI_PREF_MEMORY_BASE: | ||
413 | *value = (bridge->prefmemlimit << 16 | bridge->prefmembase); | ||
414 | break; | ||
415 | |||
416 | case PCI_PREF_BASE_UPPER32: | ||
417 | *value = bridge->prefbaseupper; | ||
418 | break; | ||
419 | |||
420 | case PCI_PREF_LIMIT_UPPER32: | ||
421 | *value = bridge->preflimitupper; | ||
422 | break; | ||
423 | |||
424 | case PCI_IO_BASE_UPPER16: | ||
425 | *value = (bridge->iolimitupper << 16 | bridge->iobaseupper); | ||
426 | break; | ||
427 | |||
428 | case PCI_ROM_ADDRESS1: | ||
429 | *value = 0; | ||
430 | break; | ||
431 | |||
432 | default: | ||
433 | *value = 0xffffffff; | ||
434 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
435 | } | ||
436 | |||
437 | if (size == 2) | ||
438 | *value = (*value >> (8 * (where & 3))) & 0xffff; | ||
439 | else if (size == 1) | ||
440 | *value = (*value >> (8 * (where & 3))) & 0xff; | ||
441 | |||
442 | return PCIBIOS_SUCCESSFUL; | ||
443 | } | ||
444 | |||
445 | /* Write to the PCI-to-PCI bridge configuration space */ | ||
446 | static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port, | ||
447 | unsigned int where, int size, u32 value) | ||
448 | { | ||
449 | struct mvebu_sw_pci_bridge *bridge = &port->bridge; | ||
450 | u32 mask, reg; | ||
451 | int err; | ||
452 | |||
453 | if (size == 4) | ||
454 | mask = 0x0; | ||
455 | else if (size == 2) | ||
456 | mask = ~(0xffff << ((where & 3) * 8)); | ||
457 | else if (size == 1) | ||
458 | mask = ~(0xff << ((where & 3) * 8)); | ||
459 | else | ||
460 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
461 | |||
462 | err = mvebu_sw_pci_bridge_read(port, where & ~3, 4, ®); | ||
463 | if (err) | ||
464 | return err; | ||
465 | |||
466 | value = (reg & mask) | value << ((where & 3) * 8); | ||
467 | |||
468 | switch (where & ~3) { | ||
469 | case PCI_COMMAND: | ||
470 | bridge->command = value & 0xffff; | ||
471 | bridge->status = value >> 16; | ||
472 | break; | ||
473 | |||
474 | case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1: | ||
475 | bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4] = value; | ||
476 | break; | ||
477 | |||
478 | case PCI_IO_BASE: | ||
479 | /* | ||
480 | * We also keep bit 1 set, it is a read-only bit that | ||
481 | * indicates we support 32 bits addressing for the | ||
482 | * I/O | ||
483 | */ | ||
484 | bridge->iobase = (value & 0xff) | PCI_IO_RANGE_TYPE_32; | ||
485 | bridge->iolimit = ((value >> 8) & 0xff) | PCI_IO_RANGE_TYPE_32; | ||
486 | bridge->secondary_status = value >> 16; | ||
487 | mvebu_pcie_handle_iobase_change(port); | ||
488 | break; | ||
489 | |||
490 | case PCI_MEMORY_BASE: | ||
491 | bridge->membase = value & 0xffff; | ||
492 | bridge->memlimit = value >> 16; | ||
493 | mvebu_pcie_handle_membase_change(port); | ||
494 | break; | ||
495 | |||
496 | case PCI_PREF_MEMORY_BASE: | ||
497 | bridge->prefmembase = value & 0xffff; | ||
498 | bridge->prefmemlimit = value >> 16; | ||
499 | break; | ||
500 | |||
501 | case PCI_PREF_BASE_UPPER32: | ||
502 | bridge->prefbaseupper = value; | ||
503 | break; | ||
504 | |||
505 | case PCI_PREF_LIMIT_UPPER32: | ||
506 | bridge->preflimitupper = value; | ||
507 | break; | ||
508 | |||
509 | case PCI_IO_BASE_UPPER16: | ||
510 | bridge->iobaseupper = value & 0xffff; | ||
511 | bridge->iolimitupper = value >> 16; | ||
512 | mvebu_pcie_handle_iobase_change(port); | ||
513 | break; | ||
514 | |||
515 | case PCI_PRIMARY_BUS: | ||
516 | bridge->primary_bus = value & 0xff; | ||
517 | bridge->secondary_bus = (value >> 8) & 0xff; | ||
518 | bridge->subordinate_bus = (value >> 16) & 0xff; | ||
519 | bridge->secondary_latency_timer = (value >> 24) & 0xff; | ||
520 | mvebu_pcie_set_local_bus_nr(port, bridge->secondary_bus); | ||
521 | break; | ||
522 | |||
523 | default: | ||
524 | break; | ||
525 | } | ||
526 | |||
527 | return PCIBIOS_SUCCESSFUL; | ||
528 | } | ||
529 | |||
530 | static inline struct mvebu_pcie *sys_to_pcie(struct pci_sys_data *sys) | ||
531 | { | ||
532 | return sys->private_data; | ||
533 | } | ||
534 | |||
535 | static struct mvebu_pcie_port * | ||
536 | mvebu_pcie_find_port(struct mvebu_pcie *pcie, struct pci_bus *bus, | ||
537 | int devfn) | ||
538 | { | ||
539 | int i; | ||
540 | |||
541 | for (i = 0; i < pcie->nports; i++) { | ||
542 | struct mvebu_pcie_port *port = &pcie->ports[i]; | ||
543 | if (bus->number == 0 && port->devfn == devfn) | ||
544 | return port; | ||
545 | if (bus->number != 0 && | ||
546 | port->bridge.secondary_bus == bus->number) | ||
547 | return port; | ||
548 | } | ||
549 | |||
550 | return NULL; | ||
551 | } | ||
552 | |||
553 | /* PCI configuration space write function */ | ||
554 | static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn, | ||
555 | int where, int size, u32 val) | ||
556 | { | ||
557 | struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata); | ||
558 | struct mvebu_pcie_port *port; | ||
559 | unsigned long flags; | ||
560 | int ret; | ||
561 | |||
562 | port = mvebu_pcie_find_port(pcie, bus, devfn); | ||
563 | if (!port) | ||
564 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
565 | |||
566 | /* Access the emulated PCI-to-PCI bridge */ | ||
567 | if (bus->number == 0) | ||
568 | return mvebu_sw_pci_bridge_write(port, where, size, val); | ||
569 | |||
570 | if (!port->haslink || PCI_SLOT(devfn) != 0) | ||
571 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
572 | |||
573 | /* Access the real PCIe interface */ | ||
574 | spin_lock_irqsave(&port->conf_lock, flags); | ||
575 | ret = mvebu_pcie_hw_wr_conf(port, bus, | ||
576 | PCI_DEVFN(1, PCI_FUNC(devfn)), | ||
577 | where, size, val); | ||
578 | spin_unlock_irqrestore(&port->conf_lock, flags); | ||
579 | |||
580 | return ret; | ||
581 | } | ||
582 | |||
583 | /* PCI configuration space read function */ | ||
584 | static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, | ||
585 | int size, u32 *val) | ||
586 | { | ||
587 | struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata); | ||
588 | struct mvebu_pcie_port *port; | ||
589 | unsigned long flags; | ||
590 | int ret; | ||
591 | |||
592 | port = mvebu_pcie_find_port(pcie, bus, devfn); | ||
593 | if (!port) { | ||
594 | *val = 0xffffffff; | ||
595 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
596 | } | ||
597 | |||
598 | /* Access the emulated PCI-to-PCI bridge */ | ||
599 | if (bus->number == 0) | ||
600 | return mvebu_sw_pci_bridge_read(port, where, size, val); | ||
601 | |||
602 | if (!port->haslink || PCI_SLOT(devfn) != 0) { | ||
603 | *val = 0xffffffff; | ||
604 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
605 | } | ||
606 | |||
607 | /* Access the real PCIe interface */ | ||
608 | spin_lock_irqsave(&port->conf_lock, flags); | ||
609 | ret = mvebu_pcie_hw_rd_conf(port, bus, | ||
610 | PCI_DEVFN(1, PCI_FUNC(devfn)), | ||
611 | where, size, val); | ||
612 | spin_unlock_irqrestore(&port->conf_lock, flags); | ||
613 | |||
614 | return ret; | ||
615 | } | ||
616 | |||
617 | static struct pci_ops mvebu_pcie_ops = { | ||
618 | .read = mvebu_pcie_rd_conf, | ||
619 | .write = mvebu_pcie_wr_conf, | ||
620 | }; | ||
621 | |||
622 | static int __init mvebu_pcie_setup(int nr, struct pci_sys_data *sys) | ||
623 | { | ||
624 | struct mvebu_pcie *pcie = sys_to_pcie(sys); | ||
625 | int i; | ||
626 | |||
627 | pci_add_resource_offset(&sys->resources, &pcie->realio, sys->io_offset); | ||
628 | pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); | ||
629 | pci_add_resource(&sys->resources, &pcie->busn); | ||
630 | |||
631 | for (i = 0; i < pcie->nports; i++) { | ||
632 | struct mvebu_pcie_port *port = &pcie->ports[i]; | ||
633 | mvebu_pcie_setup_hw(port); | ||
634 | } | ||
635 | |||
636 | return 1; | ||
637 | } | ||
638 | |||
639 | static int __init mvebu_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
640 | { | ||
641 | struct of_irq oirq; | ||
642 | int ret; | ||
643 | |||
644 | ret = of_irq_map_pci(dev, &oirq); | ||
645 | if (ret) | ||
646 | return ret; | ||
647 | |||
648 | return irq_create_of_mapping(oirq.controller, oirq.specifier, | ||
649 | oirq.size); | ||
650 | } | ||
651 | |||
652 | static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys) | ||
653 | { | ||
654 | struct mvebu_pcie *pcie = sys_to_pcie(sys); | ||
655 | struct pci_bus *bus; | ||
656 | |||
657 | bus = pci_create_root_bus(&pcie->pdev->dev, sys->busnr, | ||
658 | &mvebu_pcie_ops, sys, &sys->resources); | ||
659 | if (!bus) | ||
660 | return NULL; | ||
661 | |||
662 | pci_scan_child_bus(bus); | ||
663 | |||
664 | return bus; | ||
665 | } | ||
666 | |||
667 | resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev, | ||
668 | const struct resource *res, | ||
669 | resource_size_t start, | ||
670 | resource_size_t size, | ||
671 | resource_size_t align) | ||
672 | { | ||
673 | if (dev->bus->number != 0) | ||
674 | return start; | ||
675 | |||
676 | /* | ||
677 | * On the PCI-to-PCI bridge side, the I/O windows must have at | ||
678 | * least a 64 KB size and be aligned on their size, and the | ||
679 | * memory windows must have at least a 1 MB size and be | ||
680 | * aligned on their size | ||
681 | */ | ||
682 | if (res->flags & IORESOURCE_IO) | ||
683 | return round_up(start, max((resource_size_t)SZ_64K, size)); | ||
684 | else if (res->flags & IORESOURCE_MEM) | ||
685 | return round_up(start, max((resource_size_t)SZ_1M, size)); | ||
686 | else | ||
687 | return start; | ||
688 | } | ||
689 | |||
690 | static void __init mvebu_pcie_enable(struct mvebu_pcie *pcie) | ||
691 | { | ||
692 | struct hw_pci hw; | ||
693 | |||
694 | memset(&hw, 0, sizeof(hw)); | ||
695 | |||
696 | hw.nr_controllers = 1; | ||
697 | hw.private_data = (void **)&pcie; | ||
698 | hw.setup = mvebu_pcie_setup; | ||
699 | hw.scan = mvebu_pcie_scan_bus; | ||
700 | hw.map_irq = mvebu_pcie_map_irq; | ||
701 | hw.ops = &mvebu_pcie_ops; | ||
702 | hw.align_resource = mvebu_pcie_align_resource; | ||
703 | |||
704 | pci_common_init(&hw); | ||
705 | } | ||
706 | |||
707 | /* | ||
708 | * Looks up the list of register addresses encoded into the reg = | ||
709 | * <...> property for one that matches the given port/lane. Once | ||
710 | * found, maps it. | ||
711 | */ | ||
712 | static void __iomem * __init | ||
713 | mvebu_pcie_map_registers(struct platform_device *pdev, | ||
714 | struct device_node *np, | ||
715 | struct mvebu_pcie_port *port) | ||
716 | { | ||
717 | struct resource regs; | ||
718 | int ret = 0; | ||
719 | |||
720 | ret = of_address_to_resource(np, 0, ®s); | ||
721 | if (ret) | ||
722 | return NULL; | ||
723 | |||
724 | return devm_request_and_ioremap(&pdev->dev, ®s); | ||
725 | } | ||
726 | |||
727 | static int __init mvebu_pcie_probe(struct platform_device *pdev) | ||
728 | { | ||
729 | struct mvebu_pcie *pcie; | ||
730 | struct device_node *np = pdev->dev.of_node; | ||
731 | struct of_pci_range range; | ||
732 | struct of_pci_range_parser parser; | ||
733 | struct device_node *child; | ||
734 | int i, ret; | ||
735 | |||
736 | pcie = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pcie), | ||
737 | GFP_KERNEL); | ||
738 | if (!pcie) | ||
739 | return -ENOMEM; | ||
740 | |||
741 | pcie->pdev = pdev; | ||
742 | |||
743 | if (of_pci_range_parser_init(&parser, np)) | ||
744 | return -EINVAL; | ||
745 | |||
746 | /* Get the I/O and memory ranges from DT */ | ||
747 | for_each_of_pci_range(&parser, &range) { | ||
748 | unsigned long restype = range.flags & IORESOURCE_TYPE_BITS; | ||
749 | if (restype == IORESOURCE_IO) { | ||
750 | of_pci_range_to_resource(&range, np, &pcie->io); | ||
751 | of_pci_range_to_resource(&range, np, &pcie->realio); | ||
752 | pcie->io.name = "I/O"; | ||
753 | pcie->realio.start = max_t(resource_size_t, | ||
754 | PCIBIOS_MIN_IO, | ||
755 | range.pci_addr); | ||
756 | pcie->realio.end = min_t(resource_size_t, | ||
757 | IO_SPACE_LIMIT, | ||
758 | range.pci_addr + range.size); | ||
759 | } | ||
760 | if (restype == IORESOURCE_MEM) { | ||
761 | of_pci_range_to_resource(&range, np, &pcie->mem); | ||
762 | pcie->mem.name = "MEM"; | ||
763 | } | ||
764 | } | ||
765 | |||
766 | /* Get the bus range */ | ||
767 | ret = of_pci_parse_bus_range(np, &pcie->busn); | ||
768 | if (ret) { | ||
769 | dev_err(&pdev->dev, "failed to parse bus-range property: %d\n", | ||
770 | ret); | ||
771 | return ret; | ||
772 | } | ||
773 | |||
774 | for_each_child_of_node(pdev->dev.of_node, child) { | ||
775 | if (!of_device_is_available(child)) | ||
776 | continue; | ||
777 | pcie->nports++; | ||
778 | } | ||
779 | |||
780 | pcie->ports = devm_kzalloc(&pdev->dev, pcie->nports * | ||
781 | sizeof(struct mvebu_pcie_port), | ||
782 | GFP_KERNEL); | ||
783 | if (!pcie->ports) | ||
784 | return -ENOMEM; | ||
785 | |||
786 | i = 0; | ||
787 | for_each_child_of_node(pdev->dev.of_node, child) { | ||
788 | struct mvebu_pcie_port *port = &pcie->ports[i]; | ||
789 | |||
790 | if (!of_device_is_available(child)) | ||
791 | continue; | ||
792 | |||
793 | port->pcie = pcie; | ||
794 | |||
795 | if (of_property_read_u32(child, "marvell,pcie-port", | ||
796 | &port->port)) { | ||
797 | dev_warn(&pdev->dev, | ||
798 | "ignoring PCIe DT node, missing pcie-port property\n"); | ||
799 | continue; | ||
800 | } | ||
801 | |||
802 | if (of_property_read_u32(child, "marvell,pcie-lane", | ||
803 | &port->lane)) | ||
804 | port->lane = 0; | ||
805 | |||
806 | port->name = kasprintf(GFP_KERNEL, "pcie%d.%d", | ||
807 | port->port, port->lane); | ||
808 | |||
809 | port->devfn = of_pci_get_devfn(child); | ||
810 | if (port->devfn < 0) | ||
811 | continue; | ||
812 | |||
813 | port->base = mvebu_pcie_map_registers(pdev, child, port); | ||
814 | if (!port->base) { | ||
815 | dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n", | ||
816 | port->port, port->lane); | ||
817 | continue; | ||
818 | } | ||
819 | |||
820 | if (mvebu_pcie_link_up(port)) { | ||
821 | port->haslink = 1; | ||
822 | dev_info(&pdev->dev, "PCIe%d.%d: link up\n", | ||
823 | port->port, port->lane); | ||
824 | } else { | ||
825 | port->haslink = 0; | ||
826 | dev_info(&pdev->dev, "PCIe%d.%d: link down\n", | ||
827 | port->port, port->lane); | ||
828 | } | ||
829 | |||
830 | port->clk = of_clk_get_by_name(child, NULL); | ||
831 | if (IS_ERR(port->clk)) { | ||
832 | dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n", | ||
833 | port->port, port->lane); | ||
834 | iounmap(port->base); | ||
835 | port->haslink = 0; | ||
836 | continue; | ||
837 | } | ||
838 | |||
839 | port->dn = child; | ||
840 | |||
841 | clk_prepare_enable(port->clk); | ||
842 | spin_lock_init(&port->conf_lock); | ||
843 | |||
844 | mvebu_sw_pci_bridge_init(port); | ||
845 | |||
846 | i++; | ||
847 | } | ||
848 | |||
849 | mvebu_pcie_enable(pcie); | ||
850 | |||
851 | return 0; | ||
852 | } | ||
853 | |||
854 | static const struct of_device_id mvebu_pcie_of_match_table[] = { | ||
855 | { .compatible = "marvell,armada-xp-pcie", }, | ||
856 | { .compatible = "marvell,armada-370-pcie", }, | ||
857 | {}, | ||
858 | }; | ||
859 | MODULE_DEVICE_TABLE(of, mvebu_pcie_of_match_table); | ||
860 | |||
861 | static struct platform_driver mvebu_pcie_driver = { | ||
862 | .driver = { | ||
863 | .owner = THIS_MODULE, | ||
864 | .name = "mvebu-pcie", | ||
865 | .of_match_table = | ||
866 | of_match_ptr(mvebu_pcie_of_match_table), | ||
867 | }, | ||
868 | }; | ||
869 | |||
870 | static int __init mvebu_pcie_init(void) | ||
871 | { | ||
872 | return platform_driver_probe(&mvebu_pcie_driver, | ||
873 | mvebu_pcie_probe); | ||
874 | } | ||
875 | |||
876 | subsys_initcall(mvebu_pcie_init); | ||
877 | |||
878 | MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>"); | ||
879 | MODULE_DESCRIPTION("Marvell EBU PCIe driver"); | ||
880 | MODULE_LICENSE("GPLv2"); | ||
diff --git a/include/linux/of_address.h b/include/linux/of_address.h index 0506eb53519b..4c2e6f26432c 100644 --- a/include/linux/of_address.h +++ b/include/linux/of_address.h | |||
@@ -4,6 +4,36 @@ | |||
4 | #include <linux/errno.h> | 4 | #include <linux/errno.h> |
5 | #include <linux/of.h> | 5 | #include <linux/of.h> |
6 | 6 | ||
7 | struct of_pci_range_parser { | ||
8 | struct device_node *node; | ||
9 | const __be32 *range; | ||
10 | const __be32 *end; | ||
11 | int np; | ||
12 | int pna; | ||
13 | }; | ||
14 | |||
15 | struct of_pci_range { | ||
16 | u32 pci_space; | ||
17 | u64 pci_addr; | ||
18 | u64 cpu_addr; | ||
19 | u64 size; | ||
20 | u32 flags; | ||
21 | }; | ||
22 | |||
23 | #define for_each_of_pci_range(parser, range) \ | ||
24 | for (; of_pci_range_parser_one(parser, range);) | ||
25 | |||
26 | static inline void of_pci_range_to_resource(struct of_pci_range *range, | ||
27 | struct device_node *np, | ||
28 | struct resource *res) | ||
29 | { | ||
30 | res->flags = range->flags; | ||
31 | res->start = range->cpu_addr; | ||
32 | res->end = range->cpu_addr + range->size - 1; | ||
33 | res->parent = res->child = res->sibling = NULL; | ||
34 | res->name = np->full_name; | ||
35 | } | ||
36 | |||
7 | #ifdef CONFIG_OF_ADDRESS | 37 | #ifdef CONFIG_OF_ADDRESS |
8 | extern u64 of_translate_address(struct device_node *np, const __be32 *addr); | 38 | extern u64 of_translate_address(struct device_node *np, const __be32 *addr); |
9 | extern bool of_can_translate_address(struct device_node *dev); | 39 | extern bool of_can_translate_address(struct device_node *dev); |
@@ -27,6 +57,11 @@ static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; } | |||
27 | #define pci_address_to_pio pci_address_to_pio | 57 | #define pci_address_to_pio pci_address_to_pio |
28 | #endif | 58 | #endif |
29 | 59 | ||
60 | extern int of_pci_range_parser_init(struct of_pci_range_parser *parser, | ||
61 | struct device_node *node); | ||
62 | extern struct of_pci_range *of_pci_range_parser_one( | ||
63 | struct of_pci_range_parser *parser, | ||
64 | struct of_pci_range *range); | ||
30 | #else /* CONFIG_OF_ADDRESS */ | 65 | #else /* CONFIG_OF_ADDRESS */ |
31 | #ifndef of_address_to_resource | 66 | #ifndef of_address_to_resource |
32 | static inline int of_address_to_resource(struct device_node *dev, int index, | 67 | static inline int of_address_to_resource(struct device_node *dev, int index, |
@@ -53,6 +88,19 @@ static inline const __be32 *of_get_address(struct device_node *dev, int index, | |||
53 | { | 88 | { |
54 | return NULL; | 89 | return NULL; |
55 | } | 90 | } |
91 | |||
92 | static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser, | ||
93 | struct device_node *node) | ||
94 | { | ||
95 | return -1; | ||
96 | } | ||
97 | |||
98 | static inline struct of_pci_range *of_pci_range_parser_one( | ||
99 | struct of_pci_range_parser *parser, | ||
100 | struct of_pci_range *range) | ||
101 | { | ||
102 | return NULL; | ||
103 | } | ||
56 | #endif /* CONFIG_OF_ADDRESS */ | 104 | #endif /* CONFIG_OF_ADDRESS */ |
57 | 105 | ||
58 | 106 | ||
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h index bb115deb7612..7a04826018c0 100644 --- a/include/linux/of_pci.h +++ b/include/linux/of_pci.h | |||
@@ -10,5 +10,7 @@ int of_irq_map_pci(const struct pci_dev *pdev, struct of_irq *out_irq); | |||
10 | struct device_node; | 10 | struct device_node; |
11 | struct device_node *of_pci_find_child_device(struct device_node *parent, | 11 | struct device_node *of_pci_find_child_device(struct device_node *parent, |
12 | unsigned int devfn); | 12 | unsigned int devfn); |
13 | int of_pci_get_devfn(struct device_node *np); | ||
14 | int of_pci_parse_bus_range(struct device_node *node, struct resource *res); | ||
13 | 15 | ||
14 | #endif | 16 | #endif |