blob: f0809d35790690139a036584e1724b4aba02b8c9 [file] [log] [blame]
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -06001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13/*
14 * MSM PCIe controller driver.
15 */
16
17#define pr_fmt(fmt) "%s: " fmt, __func__
18
Steve Mucklef132c6c2012-06-06 18:30:57 -070019#include <linux/module.h>
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -060020#include <linux/bitops.h>
21#include <linux/clk.h>
22#include <linux/debugfs.h>
23#include <linux/delay.h>
24#include <linux/gpio.h>
25#include <linux/iopoll.h>
26#include <linux/kernel.h>
27#include <linux/pci.h>
28#include <linux/platform_device.h>
29#include <linux/regulator/consumer.h>
30#include <linux/types.h>
31#include <asm/mach/pci.h>
32#include <mach/gpiomux.h>
33#include <mach/hardware.h>
34#include <mach/msm_iomap.h>
35
36#include "pcie.h"
37
38/* Root Complex Port vendor/device IDs */
39#define PCIE_VENDOR_ID_RCP 0x17cb
40#define PCIE_DEVICE_ID_RCP 0x0101
41
42#define PCIE20_PARF_PCS_DEEMPH 0x34
43#define PCIE20_PARF_PCS_SWING 0x38
44#define PCIE20_PARF_PHY_CTRL 0x40
45#define PCIE20_PARF_PHY_REFCLK 0x4C
46#define PCIE20_PARF_CONFIG_BITS 0x50
47
48#define PCIE20_ELBI_SYS_CTRL 0x04
49
50#define PCIE20_CAP 0x70
51#define PCIE20_CAP_LINKCTRLSTATUS (PCIE20_CAP + 0x10)
52
53#define PCIE20_COMMAND_STATUS 0x04
54#define PCIE20_BUSNUMBERS 0x18
55#define PCIE20_MEMORY_BASE_LIMIT 0x20
56
57#define PCIE20_PLR_IATU_VIEWPORT 0x900
58#define PCIE20_PLR_IATU_CTRL1 0x904
59#define PCIE20_PLR_IATU_CTRL2 0x908
60#define PCIE20_PLR_IATU_LBAR 0x90C
61#define PCIE20_PLR_IATU_UBAR 0x910
62#define PCIE20_PLR_IATU_LAR 0x914
63#define PCIE20_PLR_IATU_LTAR 0x918
64#define PCIE20_PLR_IATU_UTAR 0x91c
65
66#define PCIE_RESET (MSM_CLK_CTL_BASE + 0x22dc)
67#define PCIE_SFAB_AXI_S5_FCLK_CTL (MSM_CLK_CTL_BASE + 0x2154)
68
69#define MSM_PCIE_DEV_BAR_ADDR PCIBIOS_MIN_MEM
70#define MSM_PCIE_DEV_CFG_ADDR 0x01000000
71
72#define RD 0
73#define WR 1
74
75/* debug mask sys interface */
76static int msm_pcie_debug_mask;
77module_param_named(debug_mask, msm_pcie_debug_mask,
78 int, S_IRUGO | S_IWUSR | S_IWGRP);
79
80/* resources from device file */
81enum msm_pcie_res {
82 MSM_PCIE_RES_PARF,
83 MSM_PCIE_RES_ELBI,
84 MSM_PCIE_RES_PCIE20,
85 MSM_PCIE_RES_AXI_BAR,
86 MSM_PCIE_RES_AXI_CONF,
87 MSM_PCIE_MAX_RES
88};
89
90/* msm pcie device data */
91static struct msm_pcie_dev_t msm_pcie_dev;
92
93/* regulators */
94static struct msm_pcie_vreg_info_t msm_pcie_vreg_info[MSM_PCIE_MAX_VREG] = {
95 {NULL, "vp_pcie", 1050000, 1050000, 40900},
96 {NULL, "vptx_pcie", 1050000, 1050000, 18200},
97 {NULL, "vdd_pcie_vph", 0, 0, 0},
98 {NULL, "pcie_ext_3p3v", 0, 0, 0}
99};
100
101/* clocks */
102static struct msm_pcie_clk_info_t msm_pcie_clk_info[MSM_PCIE_MAX_CLK] = {
103 {NULL, "bus_clk"},
104 {NULL, "iface_clk"},
105 {NULL, "ref_clk"}
106};
107
108/* resources */
109static struct msm_pcie_res_info_t msm_pcie_res_info[MSM_PCIE_MAX_RES] = {
110 {"parf", 0, 0, 0},
111 {"elbi", 0, 0, 0},
112 {"pcie20", 0, 0, 0},
113 {"axi_bar", 0, 0, 0},
114 {"axi_conf", 0, 0, 0},
115};
116
117int msm_pcie_get_debug_mask(void)
118{
119 return msm_pcie_debug_mask;
120}
121
122static void msm_pcie_write_mask(void __iomem *addr,
123 uint32_t clear_mask, uint32_t set_mask)
124{
125 uint32_t val;
126
127 val = (readl_relaxed(addr) & ~clear_mask) | set_mask;
128 writel_relaxed(val, addr);
129 wmb(); /* ensure data is written to hardware register */
130}
131
132static int msm_pcie_is_link_up(void)
133{
134 return readl_relaxed(msm_pcie_dev.pcie20 + PCIE20_CAP_LINKCTRLSTATUS) &
135 BIT(29);
136}
137
138static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,
139 int where, int size, u32 *val)
140{
141 uint32_t word_offset, byte_offset, mask;
142 uint32_t rd_val, wr_val;
143 struct msm_pcie_dev_t *dev = &msm_pcie_dev;
144 void __iomem *config_base;
145
146 /*
147 * Only buses 0 and 1 are supported. RC port on bus 0 and EP in bus 1.
148 * For downstream bus (1), make sure link is up
149 */
150 if ((bus->number > 1) || (devfn != 0)) {
151 PCIE_DBG("invalid %s - bus %d devfn %d\n",
152 (oper == RD) ? "rd" : "wr", bus->number, devfn);
153 *val = ~0;
154 return PCIBIOS_DEVICE_NOT_FOUND;
155 } else if ((bus->number != 0) && !msm_pcie_is_link_up()) {
156 PCIE_DBG("%s fail, link down - bus %d devfn %d\n",
157 (oper == RD) ? "rd" : "wr", bus->number, devfn);
158 *val = ~0;
159 return PCIBIOS_DEVICE_NOT_FOUND;
160 }
161
162 word_offset = where & ~0x3;
163 byte_offset = where & 0x3;
164 mask = (~0 >> (8 * (4 - size))) << (8 * byte_offset);
165
166 config_base = (bus->number == 0) ? dev->pcie20 : dev->axi_conf;
167 rd_val = readl_relaxed(config_base + word_offset);
168
169 if (oper == RD) {
170 *val = ((rd_val & mask) >> (8 * byte_offset));
171
172 PCIE_DBG("%d:0x%02x + 0x%04x[%d] -> 0x%08x; rd 0x%08x\n",
173 bus->number, devfn, where, size, *val, rd_val);
174 } else {
175 wr_val = (rd_val & ~mask) |
176 ((*val << (8 * byte_offset)) & mask);
177 writel_relaxed(wr_val, config_base + word_offset);
178 wmb(); /* ensure config data is written to hardware register */
179
180 PCIE_DBG("%d:0x%02x + 0x%04x[%d] <- 0x%08x;"
181 " rd 0x%08x val 0x%08x\n", bus->number,
182 devfn, where, size, wr_val, rd_val, *val);
183 }
184
185 return 0;
186}
187
188static int msm_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
189 int size, u32 *val)
190{
191 return msm_pcie_oper_conf(bus, devfn, RD, where, size, val);
192}
193
194static int msm_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
195 int where, int size, u32 val)
196{
197 return msm_pcie_oper_conf(bus, devfn, WR, where, size, &val);
198}
199
200static struct pci_ops msm_pcie_ops = {
201 .read = msm_pcie_rd_conf,
202 .write = msm_pcie_wr_conf,
203};
204
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600205static int __init msm_pcie_gpio_init(void)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600206{
207 int rc, i;
208 struct msm_pcie_gpio_info_t *info;
209
210 for (i = 0; i < MSM_PCIE_MAX_GPIO; i++) {
211 info = &msm_pcie_dev.gpio[i];
212
213 rc = gpio_request(info->num, info->name);
214 if (rc) {
215 pr_err("can't get gpio %s; %d\n", info->name, rc);
216 break;
217 }
218
219 rc = gpio_direction_output(info->num, 0);
220 if (rc) {
221 pr_err("can't set gpio direction %s; %d\n",
222 info->name, rc);
223 gpio_free(info->num);
224 break;
225 }
226 }
227
228 if (rc)
229 while (i--)
230 gpio_free(msm_pcie_dev.gpio[i].num);
231
232 return rc;
233}
234
235static void msm_pcie_gpio_deinit(void)
236{
237 int i;
238
239 for (i = 0; i < MSM_PCIE_MAX_GPIO; i++)
240 gpio_free(msm_pcie_dev.gpio[i].num);
241}
242
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600243static int __init msm_pcie_vreg_init(struct device *dev)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600244{
245 int i, rc = 0;
246 struct regulator *vreg;
247 struct msm_pcie_vreg_info_t *info;
248
249 for (i = 0; i < MSM_PCIE_MAX_VREG; i++) {
250 info = &msm_pcie_dev.vreg[i];
251
252 vreg = regulator_get(dev, info->name);
253 if (!vreg || IS_ERR(vreg)) {
254 rc = (PTR_ERR(vreg)) ? PTR_ERR(vreg) : -ENODEV;
255 pr_err("can't get %s; %d\n", info->name, rc);
256 break;
257 }
258
259 if (info->max_v) {
260 rc = regulator_set_voltage(vreg,
261 info->min_v, info->max_v);
262 if (rc) {
263 pr_err("can't set voltage %s; %d\n",
264 info->name, rc);
265 regulator_put(vreg);
266 break;
267 }
268 }
269
270 if (info->opt_mode) {
271 rc = regulator_set_optimum_mode(vreg, info->opt_mode);
272 if (rc < 0) {
273 pr_err("can't set mode %s; %d\n",
274 info->name, rc);
275 regulator_put(vreg);
276 break;
277 }
278 }
279
280 rc = regulator_enable(vreg);
281 if (rc) {
282 pr_err("can't enable %s, %d\n", info->name, rc);
283 regulator_put(vreg);
284 break;
285 }
286 info->hdl = vreg;
287 }
288
289 if (rc)
290 while (i--) {
291 regulator_disable(msm_pcie_dev.vreg[i].hdl);
292 regulator_put(msm_pcie_dev.vreg[i].hdl);
293 msm_pcie_dev.vreg[i].hdl = NULL;
294 }
295
296 return rc;
297}
298
299static void msm_pcie_vreg_deinit(void)
300{
301 int i;
302
303 for (i = 0; i < MSM_PCIE_MAX_VREG; i++) {
304 regulator_disable(msm_pcie_dev.vreg[i].hdl);
305 regulator_put(msm_pcie_dev.vreg[i].hdl);
306 msm_pcie_dev.vreg[i].hdl = NULL;
307 }
308}
309
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600310static int __init msm_pcie_clk_init(struct device *dev)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600311{
312 int i, rc = 0;
313 struct clk *clk_hdl;
314 struct msm_pcie_clk_info_t *info;
315
316 for (i = 0; i < MSM_PCIE_MAX_CLK; i++) {
317 info = &msm_pcie_dev.clk[i];
318
319 clk_hdl = clk_get(dev, info->name);
320 if (!clk_hdl || IS_ERR(clk_hdl)) {
321 rc = (PTR_ERR(clk_hdl)) ? PTR_ERR(clk_hdl) : -ENODEV;
322 pr_err("can't get clk %s; %d\n", info->name, rc);
323 break;
324 }
325 clk_prepare_enable(clk_hdl);
326 info->hdl = clk_hdl;
327 }
328
329 if (rc)
330 while (i--) {
331 clk_disable_unprepare(msm_pcie_dev.clk[i].hdl);
332 clk_put(msm_pcie_dev.clk[i].hdl);
333 msm_pcie_dev.clk[i].hdl = NULL;
334 }
335
336 return rc;
337}
338
339static void msm_pcie_clk_deinit(void)
340{
341 int i;
342
343 for (i = 0; i < MSM_PCIE_MAX_CLK; i++) {
344 clk_disable_unprepare(msm_pcie_dev.clk[i].hdl);
345 clk_put(msm_pcie_dev.clk[i].hdl);
346 msm_pcie_dev.clk[i].hdl = NULL;
347 }
348}
349
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600350static void __init msm_pcie_config_controller(void)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600351{
352 struct msm_pcie_dev_t *dev = &msm_pcie_dev;
353 struct msm_pcie_res_info_t *axi_bar = &dev->res[MSM_PCIE_RES_AXI_BAR];
354 struct msm_pcie_res_info_t *axi_conf = &dev->res[MSM_PCIE_RES_AXI_CONF];
355
356 /*
357 * program and enable address translation region 0 (device config
358 * address space); region type config;
359 * axi config address range to device config address range
360 */
361 writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_VIEWPORT);
362 /* ensure that hardware locks the region before programming it */
363 wmb();
364
365 writel_relaxed(4, dev->pcie20 + PCIE20_PLR_IATU_CTRL1);
366 writel_relaxed(BIT(31), dev->pcie20 + PCIE20_PLR_IATU_CTRL2);
367 writel_relaxed(axi_conf->start, dev->pcie20 + PCIE20_PLR_IATU_LBAR);
368 writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UBAR);
369 writel_relaxed(axi_conf->end, dev->pcie20 + PCIE20_PLR_IATU_LAR);
370 writel_relaxed(MSM_PCIE_DEV_CFG_ADDR,
371 dev->pcie20 + PCIE20_PLR_IATU_LTAR);
372 writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UTAR);
373 /* ensure that hardware registers the configuration */
374 wmb();
375
376 /*
377 * program and enable address translation region 2 (device resource
378 * address space); region type memory;
379 * axi device bar address range to device bar address range
380 */
381 writel_relaxed(2, dev->pcie20 + PCIE20_PLR_IATU_VIEWPORT);
382 /* ensure that hardware locks the region before programming it */
383 wmb();
384
385 writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_CTRL1);
386 writel_relaxed(BIT(31), dev->pcie20 + PCIE20_PLR_IATU_CTRL2);
387 writel_relaxed(axi_bar->start, dev->pcie20 + PCIE20_PLR_IATU_LBAR);
388 writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UBAR);
389 writel_relaxed(axi_bar->end, dev->pcie20 + PCIE20_PLR_IATU_LAR);
390 writel_relaxed(MSM_PCIE_DEV_BAR_ADDR,
391 dev->pcie20 + PCIE20_PLR_IATU_LTAR);
392 writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UTAR);
393 /* ensure that hardware registers the configuration */
394 wmb();
395}
396
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600397static int __init msm_pcie_get_resources(struct platform_device *pdev)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600398{
399 int i, rc = 0;
400 struct resource *res;
401 struct msm_pcie_res_info_t *info;
402 struct msm_pcie_dev_t *dev = &msm_pcie_dev;
403
404 for (i = 0; i < MSM_PCIE_MAX_RES; i++) {
405 info = &dev->res[i];
406
407 res = platform_get_resource_byname(pdev,
408 IORESOURCE_MEM, info->name);
409 if (!res) {
410 pr_err("can't get %s resource\n", info->name);
411 rc = -ENOMEM;
412 break;
413 }
414
415 info->base = ioremap(res->start, resource_size(res));
416 if (!info->base) {
417 pr_err("can't remap %s\n", info->name);
418 rc = -ENOMEM;
419 break;
420 }
421
422 info->start = res->start;
423 info->end = res->end;
424 }
425
426 if (rc) {
427 while (i--) {
428 iounmap(dev->res[i].base);
429 dev->res[i].base = NULL;
430 }
431 } else {
432 dev->parf = dev->res[MSM_PCIE_RES_PARF].base;
433 dev->elbi = dev->res[MSM_PCIE_RES_ELBI].base;
434 dev->pcie20 = dev->res[MSM_PCIE_RES_PCIE20].base;
435 dev->axi_conf = dev->res[MSM_PCIE_RES_AXI_CONF].base;
436 }
437
438 return rc;
439}
440
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600441static void msm_pcie_release_resources(void)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600442{
443 int i;
444
445 for (i = 0; i < MSM_PCIE_MAX_RES; i++) {
446 iounmap(msm_pcie_dev.res[i].base);
447 msm_pcie_dev.res[i].base = NULL;
448 }
449
450 msm_pcie_dev.parf = NULL;
451 msm_pcie_dev.elbi = NULL;
452 msm_pcie_dev.pcie20 = NULL;
453 msm_pcie_dev.axi_conf = NULL;
454}
455
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600456static int __init msm_pcie_setup(int nr, struct pci_sys_data *sys)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600457{
458 int rc;
459 struct msm_pcie_dev_t *dev = &msm_pcie_dev;
460 uint32_t val;
461
462 PCIE_DBG("bus %d\n", nr);
463 if (nr != 0)
464 return 0;
465
466 /* assert PCIe reset link to keep EP in reset */
467 gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_RST_N].num,
468 dev->gpio[MSM_PCIE_GPIO_RST_N].on);
469
470 /* enable power */
471 rc = msm_pcie_vreg_init(&dev->pdev->dev);
472 if (rc)
473 goto out;
474
475 /* assert PCIe PARF reset while powering the core */
476 msm_pcie_write_mask(PCIE_RESET, 0, BIT(2));
477
478 /* enable clocks */
479 rc = msm_pcie_clk_init(&dev->pdev->dev);
480 if (rc)
481 goto clk_fail;
482
483 /* enable pcie power; wait 3ms for clock to stabilize */
484 gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_PWR_EN].num,
485 dev->gpio[MSM_PCIE_GPIO_PWR_EN].on);
486 usleep(3000);
487
488 /*
489 * de-assert PCIe PARF reset;
490 * wait 1us before accessing PARF registers
491 */
492 msm_pcie_write_mask(PCIE_RESET, BIT(2), 0);
493 udelay(1);
494
495 /* enable PCIe clocks and resets */
496 msm_pcie_write_mask(dev->parf + PCIE20_PARF_PHY_CTRL, BIT(0), 0);
497
498 /* PARF programming */
499 writel_relaxed(0x282828, dev->parf + PCIE20_PARF_PCS_DEEMPH);
500 writel_relaxed(0x7F7F, dev->parf + PCIE20_PARF_PCS_SWING);
501 writel_relaxed((4<<24), dev->parf + PCIE20_PARF_CONFIG_BITS);
502 /* ensure that hardware registers the PARF configuration */
503 wmb();
504
505 /* enable reference clock */
506 msm_pcie_write_mask(dev->parf + PCIE20_PARF_PHY_REFCLK, 0, BIT(16));
507
508 /* enable access to PCIe slave port on system fabric */
509 writel_relaxed(BIT(4), PCIE_SFAB_AXI_S5_FCLK_CTL);
510 /* ensure that access is enabled before proceeding */
511 wmb();
512
513 /* de-assert PICe PHY, Core, POR and AXI clk domain resets */
514 msm_pcie_write_mask(PCIE_RESET, BIT(5), 0);
515 msm_pcie_write_mask(PCIE_RESET, BIT(4), 0);
516 msm_pcie_write_mask(PCIE_RESET, BIT(3), 0);
517 msm_pcie_write_mask(PCIE_RESET, BIT(0), 0);
518
519 /* wait 150ms for clock acquisition */
520 udelay(150);
521
522 /* de-assert PCIe reset link to bring EP out of reset */
523 gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_RST_N].num,
524 !dev->gpio[MSM_PCIE_GPIO_RST_N].on);
525
526 /* enable link training */
527 msm_pcie_write_mask(dev->elbi + PCIE20_ELBI_SYS_CTRL, 0, BIT(0));
528
529 /* poll for link to come up for upto 100ms */
530 rc = readl_poll_timeout(
531 (msm_pcie_dev.pcie20 + PCIE20_CAP_LINKCTRLSTATUS),
532 val, (val & BIT(29)), 10000, 100000);
533 if (rc) {
534 pr_err("link initialization failed\n");
535 goto link_fail;
536 } else
537 pr_info("link initialized\n");
538
539 msm_pcie_config_controller();
540 rc = msm_pcie_irq_init(dev);
541 if (!rc)
542 goto out;
543
544link_fail:
545 msm_pcie_clk_deinit();
546clk_fail:
547 msm_pcie_vreg_deinit();
548out:
549 return (rc) ? 0 : 1;
550}
551
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600552static struct pci_bus __init *msm_pcie_scan_bus(int nr,
553 struct pci_sys_data *sys)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600554{
555 struct pci_bus *bus = NULL;
556
557 PCIE_DBG("bus %d\n", nr);
558 if (nr == 0)
559 bus = pci_scan_bus(sys->busnr, &msm_pcie_ops, sys);
560
561 return bus;
562}
563
Steve Mucklef132c6c2012-06-06 18:30:57 -0700564static int __init msm_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600565{
566 PCIE_DBG("slot %d pin %d\n", slot, pin);
567 return (pin <= 4) ? (PCIE20_INTA + pin - 1) : 0;
568}
569
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600570static struct hw_pci msm_pci __initdata = {
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600571 .nr_controllers = 1,
572 .swizzle = pci_std_swizzle,
573 .setup = msm_pcie_setup,
574 .scan = msm_pcie_scan_bus,
575 .map_irq = msm_pcie_map_irq,
576};
577
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600578static int __init msm_pcie_probe(struct platform_device *pdev)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600579{
580 const struct msm_pcie_platform *pdata;
581 int rc;
582
583 PCIE_DBG("\n");
584
585 msm_pcie_dev.pdev = pdev;
586 pdata = pdev->dev.platform_data;
587 msm_pcie_dev.gpio = pdata->gpio;
588 msm_pcie_dev.vreg = msm_pcie_vreg_info;
589 msm_pcie_dev.clk = msm_pcie_clk_info;
590 msm_pcie_dev.res = msm_pcie_res_info;
591
592 rc = msm_pcie_get_resources(msm_pcie_dev.pdev);
593 if (rc)
594 return rc;
595
596 rc = msm_pcie_gpio_init();
597 if (rc) {
598 msm_pcie_release_resources();
599 return rc;
600 }
601
602 /* kick start ARM PCI configuration framework */
603 pci_common_init(&msm_pci);
604 return 0;
605}
606
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600607static int __exit msm_pcie_remove(struct platform_device *pdev)
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600608{
609 PCIE_DBG("\n");
610
611 msm_pcie_irq_deinit(&msm_pcie_dev);
612 msm_pcie_vreg_deinit();
613 msm_pcie_clk_deinit();
614 msm_pcie_gpio_deinit();
615 msm_pcie_release_resources();
616
617 msm_pcie_dev.pdev = NULL;
618 msm_pcie_dev.vreg = NULL;
619 msm_pcie_dev.clk = NULL;
620 msm_pcie_dev.gpio = NULL;
621 return 0;
622}
623
624static struct platform_driver msm_pcie_driver = {
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600625 .remove = __exit_p(msm_pcie_remove),
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600626 .driver = {
627 .name = "msm_pcie",
628 .owner = THIS_MODULE,
629 },
630};
631
632static int __init msm_pcie_init(void)
633{
634 PCIE_DBG("\n");
Steve Mucklef132c6c2012-06-06 18:30:57 -0700635 pcibios_min_io = 0x10000000;
636 pcibios_min_mem = 0x10000000;
Niranjana Vishwanathapurad3803302012-05-25 15:13:09 -0600637 return platform_driver_probe(&msm_pcie_driver, msm_pcie_probe);
Niranjana Vishwanathapuraf1427ac2012-05-03 14:28:21 -0600638}
639subsys_initcall(msm_pcie_init);
640
641/* RC do not represent the right class; set it to PCI_CLASS_BRIDGE_PCI */
642static void __devinit msm_pcie_fixup_header(struct pci_dev *dev)
643{
644 PCIE_DBG("hdr_type %d\n", dev->hdr_type);
645 if (dev->hdr_type == 1)
646 dev->class = (dev->class & 0xff) | (PCI_CLASS_BRIDGE_PCI << 8);
647}
648DECLARE_PCI_FIXUP_HEADER(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
649 msm_pcie_fixup_header);
650
651/*
652 * actual physical (BAR) address of the device resources starts from 0x10xxxxxx;
653 * the system axi address for the device resources starts from 0x08xxxxxx;
654 * correct the device resource structure here; address translation unit handles
655 * the required translations
656 */
657static void __devinit msm_pcie_fixup_final(struct pci_dev *dev)
658{
659 int i;
660
661 PCIE_DBG("vendor 0x%x 0x%x\n", dev->vendor, dev->device);
662 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
663 if (dev->resource[i].start & 0xFF000000) {
664 dev->resource[i].start &= 0x00FFFFFF;
665 dev->resource[i].start |= 0x08000000;
666 dev->resource[i].end &= 0x00FFFFFF;
667 dev->resource[i].end |= 0x08000000;
668 }
669 }
670}
671DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, msm_pcie_fixup_final);