aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2009-06-17 05:20:48 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-06-17 05:20:48 -0400
commit5713e602106545ff601c158d0864ce8e79de6d0a (patch)
treebba2bea5fcb88813668bc9284e54c679359ab3e6 /arch/sh
parent3d3638da49211cf15f8aec3030990ac6fba4c693 (diff)
sh: pci: Initial PCI-Express support for SH7786 Urquell board.
This adds initial support for the PCI-Express module in the SH7786, particularly as it relates to the urquell platform. Presently it is only supported in root complex mode, with endpoint mode still requiring more debugging. 29/32-bit mode and lane configurations are selectable via board mode pins, and are otherwise fixed. Only 4x and 1x PCI channels are presently handled, the PCI bridge still requires additional debugging and stabilization in hardware. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh')
-rw-r--r--arch/sh/boards/Kconfig1
-rw-r--r--arch/sh/drivers/pci/Makefile1
-rw-r--r--arch/sh/drivers/pci/pcie-sh7786.c355
3 files changed, 357 insertions, 0 deletions
diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig
index 1c91b1f565d5..2b1af0eefa6a 100644
--- a/arch/sh/boards/Kconfig
+++ b/arch/sh/boards/Kconfig
@@ -175,6 +175,7 @@ config SH_URQUELL
175 bool "Urquell" 175 bool "Urquell"
176 depends on CPU_SUBTYPE_SH7786 176 depends on CPU_SUBTYPE_SH7786
177 select ARCH_REQUIRE_GPIOLIB 177 select ARCH_REQUIRE_GPIOLIB
178 select SYS_SUPPORTS_PCI
178 179
179config SH_MIGOR 180config SH_MIGOR
180 bool "Migo-R" 181 bool "Migo-R"
diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
index d6303d0e494e..08af1f459756 100644
--- a/arch/sh/drivers/pci/Makefile
+++ b/arch/sh/drivers/pci/Makefile
@@ -25,3 +25,4 @@ obj-$(CONFIG_SH_TITAN) += fixups-titan.o
25obj-$(CONFIG_SH_LANDISK) += fixups-landisk.o 25obj-$(CONFIG_SH_LANDISK) += fixups-landisk.o
26obj-$(CONFIG_SH_LBOX_RE2) += fixups-rts7751r2d.o 26obj-$(CONFIG_SH_LBOX_RE2) += fixups-rts7751r2d.o
27obj-$(CONFIG_SH_CAYMAN) += fixups-cayman.o 27obj-$(CONFIG_SH_CAYMAN) += fixups-cayman.o
28obj-$(CONFIG_SH_URQUELL) += pcie-sh7786.o
diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c
new file mode 100644
index 000000000000..ac37ee879bab
--- /dev/null
+++ b/arch/sh/drivers/pci/pcie-sh7786.c
@@ -0,0 +1,355 @@
1/*
2 * Low-Level PCI Express Support for the SH7786
3 *
4 * Copyright (C) 2009 Paul Mundt
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10#include <linux/pci.h>
11#include <linux/init.h>
12#include <linux/kernel.h>
13#include <linux/io.h>
14#include <linux/delay.h>
15#include "pcie-sh7786.h"
16#include <asm/sizes.h>
17
18struct sh7786_pcie_port {
19 struct pci_channel *hose;
20 unsigned int index;
21 int endpoint;
22 int link;
23};
24
25static struct sh7786_pcie_port *sh7786_pcie_ports;
26static unsigned int nr_ports;
27
28static struct sh7786_pcie_hwops {
29 int (*core_init)(void);
30 int (*port_init_hw)(struct sh7786_pcie_port *port);
31} *sh7786_pcie_hwops;
32
33static struct resource sh7786_pci_32bit_mem_resources[] = {
34 {
35 .name = "pci0_mem",
36 .start = SH4A_PCIMEM_BASEA,
37 .end = SH4A_PCIMEM_BASEA + SZ_64M - 1,
38 .flags = IORESOURCE_MEM,
39 }, {
40 .name = "pci1_mem",
41 .start = SH4A_PCIMEM_BASEA1,
42 .end = SH4A_PCIMEM_BASEA1 + SZ_64M - 1,
43 .flags = IORESOURCE_MEM,
44 }, {
45 .name = "pci2_mem",
46 .start = SH4A_PCIMEM_BASEA2,
47 .end = SH4A_PCIMEM_BASEA2 + SZ_64M - 1,
48 .flags = IORESOURCE_MEM,
49 },
50};
51
52static struct resource sh7786_pci_29bit_mem_resource = {
53 .start = SH4A_PCIMEM_BASE,
54 .end = SH4A_PCIMEM_BASE + SZ_64M - 1,
55 .flags = IORESOURCE_MEM,
56};
57
58static struct resource sh7786_pci_io_resources[] = {
59 {
60 .name = "pci0_io",
61 .start = SH4A_PCIIO_BASE,
62 .end = SH4A_PCIIO_BASE + SZ_8M - 1,
63 .flags = IORESOURCE_IO,
64 }, {
65 .name = "pci1_io",
66 .start = SH4A_PCIIO_BASE1,
67 .end = SH4A_PCIIO_BASE1 + SZ_8M - 1,
68 .flags = IORESOURCE_IO,
69 }, {
70 .name = "pci2_io",
71 .start = SH4A_PCIIO_BASE2,
72 .end = SH4A_PCIIO_BASE2 + SZ_4M - 1,
73 .flags = IORESOURCE_IO,
74 },
75};
76
77extern struct pci_ops sh7786_pci_ops;
78
79#define DEFINE_CONTROLLER(start, idx) \
80{ \
81 .pci_ops = &sh7786_pci_ops, \
82 .reg_base = start, \
83 /* mem_resource filled in at probe time */ \
84 .mem_offset = 0, \
85 .io_resource = &sh7786_pci_io_resources[idx], \
86 .io_offset = 0, \
87}
88
89static struct pci_channel sh7786_pci_channels[] = {
90 DEFINE_CONTROLLER(0xfe000000, 0),
91 DEFINE_CONTROLLER(0xfe200000, 1),
92 DEFINE_CONTROLLER(0xfcc00000, 2),
93};
94
95static int phy_wait_for_ack(struct pci_channel *chan)
96{
97 unsigned int timeout = 100;
98
99 while (timeout--) {
100 if (pci_read_reg(chan, SH4A_PCIEPHYADRR) & (1 << BITS_ACK))
101 return 0;
102
103 udelay(100);
104 }
105
106 return -ETIMEDOUT;
107}
108
109static int pci_wait_for_irq(struct pci_channel *chan, unsigned int mask)
110{
111 unsigned int timeout = 100;
112
113 while (timeout--) {
114 if ((pci_read_reg(chan, SH4A_PCIEINTR) & mask) == mask)
115 return 0;
116
117 udelay(100);
118 }
119
120 return -ETIMEDOUT;
121}
122
123static void phy_write_reg(struct pci_channel *chan, unsigned int addr,
124 unsigned int lane, unsigned int data)
125{
126 unsigned long phyaddr, ctrl;
127
128 phyaddr = (1 << BITS_CMD) + ((lane & 0xf) << BITS_LANE) +
129 ((addr & 0xff) << BITS_ADR);
130
131 /* Enable clock */
132 ctrl = pci_read_reg(chan, SH4A_PCIEPHYCTLR);
133 ctrl |= (1 << BITS_CKE);
134 pci_write_reg(chan, ctrl, SH4A_PCIEPHYCTLR);
135
136 /* Set write data */
137 pci_write_reg(chan, data, SH4A_PCIEPHYDOUTR);
138 pci_write_reg(chan, phyaddr, SH4A_PCIEPHYADRR);
139
140 phy_wait_for_ack(chan);
141
142 /* Clear command */
143 pci_write_reg(chan, 0, SH4A_PCIEPHYADRR);
144
145 phy_wait_for_ack(chan);
146
147 /* Disable clock */
148 ctrl = pci_read_reg(chan, SH4A_PCIEPHYCTLR);
149 ctrl &= ~(1 << BITS_CKE);
150 pci_write_reg(chan, ctrl, SH4A_PCIEPHYCTLR);
151}
152
153static int phy_init(struct pci_channel *chan)
154{
155 unsigned int timeout = 100;
156
157 /* Initialize the phy */
158 phy_write_reg(chan, 0x60, 0xf, 0x004b008b);
159 phy_write_reg(chan, 0x61, 0xf, 0x00007b41);
160 phy_write_reg(chan, 0x64, 0xf, 0x00ff4f00);
161 phy_write_reg(chan, 0x65, 0xf, 0x09070907);
162 phy_write_reg(chan, 0x66, 0xf, 0x00000010);
163 phy_write_reg(chan, 0x74, 0xf, 0x0007001c);
164 phy_write_reg(chan, 0x79, 0xf, 0x01fc000d);
165
166 /* Deassert Standby */
167 phy_write_reg(chan, 0x67, 0xf, 0x00000400);
168
169 while (timeout--) {
170 if (pci_read_reg(chan, SH4A_PCIEPHYSR))
171 return 0;
172
173 udelay(100);
174 }
175
176 return -ETIMEDOUT;
177}
178
179static int pcie_init(struct sh7786_pcie_port *port)
180{
181 struct pci_channel *chan = port->hose;
182 unsigned int data;
183 int ret;
184
185 /* Begin initialization */
186 pci_write_reg(chan, 0, SH4A_PCIETCTLR);
187
188 /* Initialize as type1. */
189 data = pci_read_reg(chan, SH4A_PCIEPCICONF3);
190 data &= ~(0x7f << 16);
191 data |= PCI_HEADER_TYPE_BRIDGE << 16;
192 pci_write_reg(chan, data, SH4A_PCIEPCICONF3);
193
194 /* Initialize default capabilities. */
195 data = pci_read_reg(chan, SH4A_PCIEEXPCAP0);
196 data &= ~(PCI_EXP_FLAGS_TYPE << 16);
197
198 if (port->endpoint)
199 data |= PCI_EXP_TYPE_ENDPOINT << 20;
200 else
201 data |= PCI_EXP_TYPE_ROOT_PORT << 20;
202
203 data |= PCI_CAP_ID_EXP;
204 pci_write_reg(chan, data, SH4A_PCIEEXPCAP0);
205
206 /* Enable x4 link width and extended sync. */
207 data = pci_read_reg(chan, SH4A_PCIEEXPCAP4);
208 data &= ~(PCI_EXP_LNKSTA_NLW << 16);
209 data |= (1 << 22) | PCI_EXP_LNKCTL_ES;
210 pci_write_reg(chan, data, SH4A_PCIEEXPCAP4);
211
212 /* Set the completion timer timeout to the maximum 32ms. */
213 data = pci_read_reg(chan, SH4A_PCIETLCTLR);
214 data &= ~0xffff;
215 data |= 0x32 << 8;
216 pci_write_reg(chan, data, SH4A_PCIETLCTLR);
217
218 /*
219 * Set fast training sequences to the maximum 255,
220 * and enable MAC data scrambling.
221 */
222 data = pci_read_reg(chan, SH4A_PCIEMACCTLR);
223 data &= ~PCIEMACCTLR_SCR_DIS;
224 data |= (0xff << 16);
225 pci_write_reg(chan, data, SH4A_PCIEMACCTLR);
226
227 /* Finish initialization */
228 data = pci_read_reg(chan, SH4A_PCIETCTLR);
229 data |= 0x1;
230 pci_write_reg(chan, data, SH4A_PCIETCTLR);
231
232 /* Enable DL_Active Interrupt generation */
233 data = pci_read_reg(chan, SH4A_PCIEDLINTENR);
234 data |= PCIEDLINTENR_DLL_ACT_ENABLE;
235 pci_write_reg(chan, data, SH4A_PCIEDLINTENR);
236
237 /* Disable MAC data scrambling. */
238 data = pci_read_reg(chan, SH4A_PCIEMACCTLR);
239 data |= PCIEMACCTLR_SCR_DIS | (0xff << 16);
240 pci_write_reg(chan, data, SH4A_PCIEMACCTLR);
241
242 ret = pci_wait_for_irq(chan, MASK_INT_TX_CTRL);
243 if (unlikely(ret != 0))
244 return -ENODEV;
245
246 pci_write_reg(chan, 0x00100007, SH4A_PCIEPCICONF1);
247 pci_write_reg(chan, 0x80888000, SH4A_PCIETXVC0DCTLR);
248 pci_write_reg(chan, 0x00222000, SH4A_PCIERXVC0DCTLR);
249 pci_write_reg(chan, 0x000050A0, SH4A_PCIEEXPCAP2);
250
251 wmb();
252
253 data = pci_read_reg(chan, SH4A_PCIEMACSR);
254 printk(KERN_NOTICE "PCI: PCIe#%d link width %d\n",
255 port->index, (data >> 20) & 0x3f);
256
257 pci_write_reg(chan, 0x007c0000, SH4A_PCIEPAMR0);
258 pci_write_reg(chan, 0x00000000, SH4A_PCIEPARH0);
259 pci_write_reg(chan, 0x00000000, SH4A_PCIEPARL0);
260 pci_write_reg(chan, 0x80000100, SH4A_PCIEPTCTLR0);
261
262 pci_write_reg(chan, 0x03fc0000, SH4A_PCIEPAMR2);
263 pci_write_reg(chan, 0x00000000, SH4A_PCIEPARH2);
264 pci_write_reg(chan, 0x00000000, SH4A_PCIEPARL2);
265 pci_write_reg(chan, 0x80000000, SH4A_PCIEPTCTLR2);
266
267 return 0;
268}
269
270int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
271{
272 return 71;
273}
274
275static int sh7786_pcie_core_init(void)
276{
277 /* Return the number of ports */
278 return test_mode_pin(MODE_PIN12) ? 3 : 2;
279}
280
281static int __devinit sh7786_pcie_init_hw(struct sh7786_pcie_port *port)
282{
283 int ret;
284
285 ret = phy_init(port->hose);
286 if (unlikely(ret < 0))
287 return ret;
288
289 /*
290 * Check if we are configured in endpoint or root complex mode,
291 * this is a fixed pin setting that applies to all PCIe ports.
292 */
293 port->endpoint = test_mode_pin(MODE_PIN11);
294
295 ret = pcie_init(port);
296 if (unlikely(ret < 0))
297 return ret;
298
299 register_pci_controller(port->hose);
300
301 return 0;
302}
303
304static struct sh7786_pcie_hwops sh7786_65nm_pcie_hwops __initdata = {
305 .core_init = sh7786_pcie_core_init,
306 .port_init_hw = sh7786_pcie_init_hw,
307};
308
309static int __init sh7786_pcie_init(void)
310{
311 int ret = 0, i;
312
313 printk(KERN_NOTICE "PCI: Starting intialization.\n");
314
315 sh7786_pcie_hwops = &sh7786_65nm_pcie_hwops;
316
317 nr_ports = sh7786_pcie_hwops->core_init();
318 BUG_ON(nr_ports > ARRAY_SIZE(sh7786_pci_channels));
319
320 if (unlikely(nr_ports == 0))
321 return -ENODEV;
322
323 sh7786_pcie_ports = kzalloc(nr_ports * sizeof(struct sh7786_pcie_port),
324 GFP_KERNEL);
325 if (unlikely(!sh7786_pcie_ports))
326 return -ENOMEM;
327
328 printk(KERN_NOTICE "PCI: probing %d ports.\n", nr_ports);
329
330 for (i = 0; i < nr_ports; i++) {
331 struct sh7786_pcie_port *port = sh7786_pcie_ports + i;
332
333 port->index = i;
334 port->hose = sh7786_pci_channels + i;
335 port->hose->io_map_base = port->hose->io_resource->start;
336
337 /*
338 * Check if we are booting in 29 or 32-bit mode
339 *
340 * 32-bit mode provides each controller with its own
341 * memory window, while 29-bit mode uses a shared one.
342 */
343 port->hose->mem_resource = test_mode_pin(MODE_PIN10) ?
344 &sh7786_pci_32bit_mem_resources[i] :
345 &sh7786_pci_29bit_mem_resource;
346
347 ret |= sh7786_pcie_hwops->port_init_hw(port);
348 }
349
350 if (unlikely(ret))
351 return ret;
352
353 return 0;
354}
355arch_initcall(sh7786_pcie_init);