diff options
author | John Crispin <blogic@openwrt.org> | 2012-05-11 12:47:30 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2012-05-21 09:31:52 -0400 |
commit | 57c8cb8f242988b8048a7058cd1edde025c6f232 (patch) | |
tree | 980f3ad2b686d8959312d9a5858b879aa58bcd49 | |
parent | ddd4eeca961cc6b1d57e0ca2f264403d690b6882 (diff) |
MIPS: pci: convert lantiq driver to OF
Implement support for OF inside the lantiq PCI driver. The patch also splits
pcibios_plat_dev_init and pcibios_map_irq out into their own file to accomodate
coexistance with the upcoming pcie driver.
Signed-off-by: John Crispin <blogic@openwrt.org>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/3806/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r-- | arch/mips/lantiq/Kconfig | 5 | ||||
-rw-r--r-- | arch/mips/pci/Makefile | 3 | ||||
-rw-r--r-- | arch/mips/pci/fixup-lantiq.c | 40 | ||||
-rw-r--r-- | arch/mips/pci/pci-lantiq.c | 177 |
4 files changed, 131 insertions, 94 deletions
diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig index 9485fe54752b..7389098fd983 100644 --- a/arch/mips/lantiq/Kconfig +++ b/arch/mips/lantiq/Kconfig | |||
@@ -18,7 +18,6 @@ config SOC_XWAY | |||
18 | select HW_HAS_PCI | 18 | select HW_HAS_PCI |
19 | endchoice | 19 | endchoice |
20 | 20 | ||
21 | |||
22 | choice | 21 | choice |
23 | prompt "Devicetree" | 22 | prompt "Devicetree" |
24 | 23 | ||
@@ -27,4 +26,8 @@ config DT_EASY50712 | |||
27 | depends on SOC_XWAY | 26 | depends on SOC_XWAY |
28 | endchoice | 27 | endchoice |
29 | 28 | ||
29 | config PCI_LANTIQ | ||
30 | bool "PCI Support" | ||
31 | depends on SOC_XWAY && PCI | ||
32 | |||
30 | endif | 33 | endif |
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index c3ac4b086eb2..499a019c2c5f 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile | |||
@@ -41,7 +41,8 @@ obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o | |||
41 | obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o | 41 | obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o |
42 | obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o | 42 | obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o |
43 | obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o | 43 | obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o |
44 | obj-$(CONFIG_SOC_XWAY) += pci-lantiq.o ops-lantiq.o | 44 | obj-$(CONFIG_LANTIQ) += fixup-lantiq.o |
45 | obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o | ||
45 | obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o | 46 | obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o |
46 | obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o | 47 | obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o |
47 | obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o | 48 | obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o |
diff --git a/arch/mips/pci/fixup-lantiq.c b/arch/mips/pci/fixup-lantiq.c new file mode 100644 index 000000000000..6c829df28dc7 --- /dev/null +++ b/arch/mips/pci/fixup-lantiq.c | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify it | ||
3 | * under the terms of the GNU General Public License version 2 as published | ||
4 | * by the Free Software Foundation. | ||
5 | * | ||
6 | * Copyright (C) 2012 John Crispin <blogic@openwrt.org> | ||
7 | */ | ||
8 | |||
9 | #include <linux/of_irq.h> | ||
10 | #include <linux/of_pci.h> | ||
11 | |||
12 | int (*ltq_pci_plat_arch_init)(struct pci_dev *dev) = NULL; | ||
13 | int (*ltq_pci_plat_dev_init)(struct pci_dev *dev) = NULL; | ||
14 | |||
15 | int pcibios_plat_dev_init(struct pci_dev *dev) | ||
16 | { | ||
17 | if (ltq_pci_plat_arch_init) | ||
18 | return ltq_pci_plat_arch_init(dev); | ||
19 | |||
20 | if (ltq_pci_plat_dev_init) | ||
21 | return ltq_pci_plat_dev_init(dev); | ||
22 | |||
23 | return 0; | ||
24 | } | ||
25 | |||
26 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
27 | { | ||
28 | struct of_irq dev_irq; | ||
29 | int irq; | ||
30 | |||
31 | if (of_irq_map_pci(dev, &dev_irq)) { | ||
32 | dev_err(&dev->dev, "trying to map irq for unknown slot:%d pin:%d\n", | ||
33 | slot, pin); | ||
34 | return 0; | ||
35 | } | ||
36 | irq = irq_create_of_mapping(dev_irq.controller, dev_irq.specifier, | ||
37 | dev_irq.size); | ||
38 | dev_info(&dev->dev, "SLOT:%d PIN:%d IRQ:%d\n", slot, pin, irq); | ||
39 | return irq; | ||
40 | } | ||
diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c index 4d8c49beeda4..ea453532a33c 100644 --- a/arch/mips/pci/pci-lantiq.c +++ b/arch/mips/pci/pci-lantiq.c | |||
@@ -13,8 +13,12 @@ | |||
13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
14 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
15 | #include <linux/vmalloc.h> | 15 | #include <linux/vmalloc.h> |
16 | #include <linux/export.h> | 16 | #include <linux/module.h> |
17 | #include <linux/platform_device.h> | 17 | #include <linux/clk.h> |
18 | #include <linux/of_platform.h> | ||
19 | #include <linux/of_gpio.h> | ||
20 | #include <linux/of_irq.h> | ||
21 | #include <linux/of_pci.h> | ||
18 | 22 | ||
19 | #include <asm/pci.h> | 23 | #include <asm/pci.h> |
20 | #include <asm/gpio.h> | 24 | #include <asm/gpio.h> |
@@ -22,17 +26,9 @@ | |||
22 | 26 | ||
23 | #include <lantiq_soc.h> | 27 | #include <lantiq_soc.h> |
24 | #include <lantiq_irq.h> | 28 | #include <lantiq_irq.h> |
25 | #include <lantiq_platform.h> | ||
26 | 29 | ||
27 | #include "pci-lantiq.h" | 30 | #include "pci-lantiq.h" |
28 | 31 | ||
29 | #define LTQ_PCI_CFG_BASE 0x17000000 | ||
30 | #define LTQ_PCI_CFG_SIZE 0x00008000 | ||
31 | #define LTQ_PCI_MEM_BASE 0x18000000 | ||
32 | #define LTQ_PCI_MEM_SIZE 0x02000000 | ||
33 | #define LTQ_PCI_IO_BASE 0x1AE00000 | ||
34 | #define LTQ_PCI_IO_SIZE 0x00200000 | ||
35 | |||
36 | #define PCI_CR_FCI_ADDR_MAP0 0x00C0 | 32 | #define PCI_CR_FCI_ADDR_MAP0 0x00C0 |
37 | #define PCI_CR_FCI_ADDR_MAP1 0x00C4 | 33 | #define PCI_CR_FCI_ADDR_MAP1 0x00C4 |
38 | #define PCI_CR_FCI_ADDR_MAP2 0x00C8 | 34 | #define PCI_CR_FCI_ADDR_MAP2 0x00C8 |
@@ -71,50 +67,24 @@ | |||
71 | __iomem void *ltq_pci_mapped_cfg; | 67 | __iomem void *ltq_pci_mapped_cfg; |
72 | static __iomem void *ltq_pci_membase; | 68 | static __iomem void *ltq_pci_membase; |
73 | 69 | ||
74 | int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL; | 70 | static int reset_gpio; |
75 | 71 | static struct clk *clk_pci, *clk_external; | |
76 | /* Since the PCI REQ pins can be reused for other functionality, make it | 72 | static struct resource pci_io_resource; |
77 | possible to exclude those from interpretation by the PCI controller */ | 73 | static struct resource pci_mem_resource; |
78 | static int ltq_pci_req_mask = 0xf; | 74 | static struct pci_ops pci_ops = { |
79 | |||
80 | static int *ltq_pci_irq_map; | ||
81 | |||
82 | struct pci_ops ltq_pci_ops = { | ||
83 | .read = ltq_pci_read_config_dword, | 75 | .read = ltq_pci_read_config_dword, |
84 | .write = ltq_pci_write_config_dword | 76 | .write = ltq_pci_write_config_dword |
85 | }; | 77 | }; |
86 | 78 | ||
87 | static struct resource pci_io_resource = { | 79 | static struct pci_controller pci_controller = { |
88 | .name = "pci io space", | 80 | .pci_ops = &pci_ops, |
89 | .start = LTQ_PCI_IO_BASE, | ||
90 | .end = LTQ_PCI_IO_BASE + LTQ_PCI_IO_SIZE - 1, | ||
91 | .flags = IORESOURCE_IO | ||
92 | }; | ||
93 | |||
94 | static struct resource pci_mem_resource = { | ||
95 | .name = "pci memory space", | ||
96 | .start = LTQ_PCI_MEM_BASE, | ||
97 | .end = LTQ_PCI_MEM_BASE + LTQ_PCI_MEM_SIZE - 1, | ||
98 | .flags = IORESOURCE_MEM | ||
99 | }; | ||
100 | |||
101 | static struct pci_controller ltq_pci_controller = { | ||
102 | .pci_ops = <q_pci_ops, | ||
103 | .mem_resource = &pci_mem_resource, | 81 | .mem_resource = &pci_mem_resource, |
104 | .mem_offset = 0x00000000UL, | 82 | .mem_offset = 0x00000000UL, |
105 | .io_resource = &pci_io_resource, | 83 | .io_resource = &pci_io_resource, |
106 | .io_offset = 0x00000000UL, | 84 | .io_offset = 0x00000000UL, |
107 | }; | 85 | }; |
108 | 86 | ||
109 | int pcibios_plat_dev_init(struct pci_dev *dev) | 87 | static inline u32 ltq_calc_bar11mask(void) |
110 | { | ||
111 | if (ltqpci_plat_dev_init) | ||
112 | return ltqpci_plat_dev_init(dev); | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static u32 ltq_calc_bar11mask(void) | ||
118 | { | 88 | { |
119 | u32 mem, bar11mask; | 89 | u32 mem, bar11mask; |
120 | 90 | ||
@@ -125,32 +95,42 @@ static u32 ltq_calc_bar11mask(void) | |||
125 | return bar11mask; | 95 | return bar11mask; |
126 | } | 96 | } |
127 | 97 | ||
128 | static int __devinit ltq_pci_startup(struct ltq_pci_data *conf) | 98 | static int __devinit ltq_pci_startup(struct platform_device *pdev) |
129 | { | 99 | { |
100 | struct device_node *node = pdev->dev.of_node; | ||
101 | const __be32 *req_mask, *bus_clk; | ||
130 | u32 temp_buffer; | 102 | u32 temp_buffer; |
131 | 103 | ||
132 | /* set clock to 33Mhz */ | 104 | /* get our clocks */ |
133 | if (ltq_is_ar9()) { | 105 | clk_pci = clk_get(&pdev->dev, NULL); |
134 | ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0x1f00000, LTQ_CGU_IFCCR); | 106 | if (IS_ERR(clk_pci)) { |
135 | ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0xe00000, LTQ_CGU_IFCCR); | 107 | dev_err(&pdev->dev, "failed to get pci clock\n"); |
136 | } else { | 108 | return PTR_ERR(clk_pci); |
137 | ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR); | ||
138 | ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR); | ||
139 | } | 109 | } |
140 | 110 | ||
141 | /* external or internal clock ? */ | 111 | clk_external = clk_get(&pdev->dev, "external"); |
142 | if (conf->clock) { | 112 | if (IS_ERR(clk_external)) { |
143 | ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~(1 << 16), | 113 | clk_put(clk_pci); |
144 | LTQ_CGU_IFCCR); | 114 | dev_err(&pdev->dev, "failed to get external pci clock\n"); |
145 | ltq_cgu_w32((1 << 30), LTQ_CGU_PCICR); | 115 | return PTR_ERR(clk_external); |
146 | } else { | ||
147 | ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | (1 << 16), | ||
148 | LTQ_CGU_IFCCR); | ||
149 | ltq_cgu_w32((1 << 31) | (1 << 30), LTQ_CGU_PCICR); | ||
150 | } | 116 | } |
151 | 117 | ||
152 | /* setup pci clock and gpis used by pci */ | 118 | /* read the bus speed that we want */ |
153 | gpio_request(21, "pci-reset"); | 119 | bus_clk = of_get_property(node, "lantiq,bus-clock", NULL); |
120 | if (bus_clk) | ||
121 | clk_set_rate(clk_pci, *bus_clk); | ||
122 | |||
123 | /* and enable the clocks */ | ||
124 | clk_enable(clk_pci); | ||
125 | if (of_find_property(node, "lantiq,external-clock", NULL)) | ||
126 | clk_enable(clk_external); | ||
127 | else | ||
128 | clk_disable(clk_external); | ||
129 | |||
130 | /* setup reset gpio used by pci */ | ||
131 | reset_gpio = of_get_named_gpio(node, "gpio-reset", 0); | ||
132 | if (reset_gpio > 0) | ||
133 | devm_gpio_request(&pdev->dev, reset_gpio, "pci-reset"); | ||
154 | 134 | ||
155 | /* enable auto-switching between PCI and EBU */ | 135 | /* enable auto-switching between PCI and EBU */ |
156 | ltq_pci_w32(0xa, PCI_CR_CLK_CTRL); | 136 | ltq_pci_w32(0xa, PCI_CR_CLK_CTRL); |
@@ -163,7 +143,12 @@ static int __devinit ltq_pci_startup(struct ltq_pci_data *conf) | |||
163 | 143 | ||
164 | /* enable external 2 PCI masters */ | 144 | /* enable external 2 PCI masters */ |
165 | temp_buffer = ltq_pci_r32(PCI_CR_PC_ARB); | 145 | temp_buffer = ltq_pci_r32(PCI_CR_PC_ARB); |
166 | temp_buffer &= (~(ltq_pci_req_mask << 16)); | 146 | /* setup the request mask */ |
147 | req_mask = of_get_property(node, "req-mask", NULL); | ||
148 | if (req_mask) | ||
149 | temp_buffer &= ~((*req_mask & 0xf) << 16); | ||
150 | else | ||
151 | temp_buffer &= ~0xf0000; | ||
167 | /* enable internal arbiter */ | 152 | /* enable internal arbiter */ |
168 | temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT); | 153 | temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT); |
169 | /* enable internal PCI master reqest */ | 154 | /* enable internal PCI master reqest */ |
@@ -207,47 +192,55 @@ static int __devinit ltq_pci_startup(struct ltq_pci_data *conf) | |||
207 | ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN); | 192 | ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN); |
208 | 193 | ||
209 | /* toggle reset pin */ | 194 | /* toggle reset pin */ |
210 | __gpio_set_value(21, 0); | 195 | if (reset_gpio > 0) { |
211 | wmb(); | 196 | __gpio_set_value(reset_gpio, 0); |
212 | mdelay(1); | 197 | wmb(); |
213 | __gpio_set_value(21, 1); | 198 | mdelay(1); |
214 | return 0; | 199 | __gpio_set_value(reset_gpio, 1); |
215 | } | 200 | } |
216 | |||
217 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
218 | { | ||
219 | if (ltq_pci_irq_map[slot]) | ||
220 | return ltq_pci_irq_map[slot]; | ||
221 | printk(KERN_ERR "lq_pci: trying to map irq for unknown slot %d\n", | ||
222 | slot); | ||
223 | |||
224 | return 0; | 201 | return 0; |
225 | } | 202 | } |
226 | 203 | ||
227 | static int __devinit ltq_pci_probe(struct platform_device *pdev) | 204 | static int __devinit ltq_pci_probe(struct platform_device *pdev) |
228 | { | 205 | { |
229 | struct ltq_pci_data *ltq_pci_data = | 206 | struct resource *res_cfg, *res_bridge; |
230 | (struct ltq_pci_data *) pdev->dev.platform_data; | ||
231 | 207 | ||
232 | pci_clear_flags(PCI_PROBE_ONLY); | 208 | pci_clear_flags(PCI_PROBE_ONLY); |
233 | ltq_pci_irq_map = ltq_pci_data->irq; | ||
234 | ltq_pci_membase = ioremap_nocache(PCI_CR_BASE_ADDR, PCI_CR_SIZE); | ||
235 | ltq_pci_mapped_cfg = | ||
236 | ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE); | ||
237 | ltq_pci_controller.io_map_base = | ||
238 | (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1); | ||
239 | ltq_pci_startup(ltq_pci_data); | ||
240 | register_pci_controller(<q_pci_controller); | ||
241 | 209 | ||
210 | res_cfg = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
211 | res_bridge = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
212 | if (!res_cfg || !res_bridge) { | ||
213 | dev_err(&pdev->dev, "missing memory reources\n"); | ||
214 | return -EINVAL; | ||
215 | } | ||
216 | |||
217 | ltq_pci_membase = devm_request_and_ioremap(&pdev->dev, res_bridge); | ||
218 | ltq_pci_mapped_cfg = devm_request_and_ioremap(&pdev->dev, res_cfg); | ||
219 | |||
220 | if (!ltq_pci_membase || !ltq_pci_mapped_cfg) { | ||
221 | dev_err(&pdev->dev, "failed to remap resources\n"); | ||
222 | return -ENOMEM; | ||
223 | } | ||
224 | |||
225 | ltq_pci_startup(pdev); | ||
226 | |||
227 | pci_load_of_ranges(&pci_controller, pdev->dev.of_node); | ||
228 | register_pci_controller(&pci_controller); | ||
242 | return 0; | 229 | return 0; |
243 | } | 230 | } |
244 | 231 | ||
245 | static struct platform_driver | 232 | static const struct of_device_id ltq_pci_match[] = { |
246 | ltq_pci_driver = { | 233 | { .compatible = "lantiq,pci-xway" }, |
234 | {}, | ||
235 | }; | ||
236 | MODULE_DEVICE_TABLE(of, ltq_pci_match); | ||
237 | |||
238 | static struct platform_driver ltq_pci_driver = { | ||
247 | .probe = ltq_pci_probe, | 239 | .probe = ltq_pci_probe, |
248 | .driver = { | 240 | .driver = { |
249 | .name = "ltq_pci", | 241 | .name = "pci-xway", |
250 | .owner = THIS_MODULE, | 242 | .owner = THIS_MODULE, |
243 | .of_match_table = ltq_pci_match, | ||
251 | }, | 244 | }, |
252 | }; | 245 | }; |
253 | 246 | ||
@@ -255,7 +248,7 @@ int __init pcibios_init(void) | |||
255 | { | 248 | { |
256 | int ret = platform_driver_register(<q_pci_driver); | 249 | int ret = platform_driver_register(<q_pci_driver); |
257 | if (ret) | 250 | if (ret) |
258 | printk(KERN_INFO "ltq_pci: Error registering platfom driver!"); | 251 | pr_info("pci-xway: Error registering platform driver!"); |
259 | return ret; | 252 | return ret; |
260 | } | 253 | } |
261 | 254 | ||